DEV Community

Yoha
Yoha

Posted on

How to create truly const object in JavaScript?

We create an object person with name Harry and try to reassign it to an object with name Ron.

const person = {
  name: 'Harry'
}

// Uncaught TypeError: Assignment to constant variable.
person = {
  name: 'Ron'
}
Enter fullscreen mode Exit fullscreen mode

We can't do it and get an error because we use const statement.

But what if we change the property directly of this object?
Although we use const, we can do it, so we don't get a truly constant object.

const person = {
  name: 'Harry'
}

person.name = 'Ron'

console.log(person) // { name: 'Ron }
Enter fullscreen mode Exit fullscreen mode

But good news, I will show you how to fix it.

We just need to wrap object by 'Object.freeze' from JavaScript standard library.

const person = Object.freeze({
  name: 'Harry'
})

person.name = 'Ron'

console.log(person) // { name: 'Harry' }
Enter fullscreen mode Exit fullscreen mode

Now we can't change property of this object. Also, it's good to know that in JavaScript strict mode we get an error if we try to change a frozen object.

'use strict'

const person = Object.freeze({
  name: 'Harry'
})

// Uncaught TypeError: Cannot assign to read only property
person.name = 'Ron'
Enter fullscreen mode Exit fullscreen mode

Deep objects

But what if we have an object with nested structured?

const person = Object.freeze({ 
  city: { name: 'London' } 
})

person.city.name = 'New York'

console.log(person) // { city: { name: 'New York' } }

Enter fullscreen mode Exit fullscreen mode

Again we have the same problem. Object.freeze works only for first level properties, not affecting to deeper levels. Good news, that it's easy to fix. We just need to create function which recursively freeze all levels object.

function deepFreeze(obj) {
  Object.freeze(obj);
  Object.getOwnPropertyNames(obj).forEach((prop) => {
    const value = obj[prop];
    if (
      typeof value === 'object' && 
      value !== null && 
      !Object.isFrozen(value)
    ) {
      deepFreeze(value);
    }
  });
  return obj;
}

const person = Object.freeze({ 
  city: { name: 'London' } 
})

// Uncaught TypeError: Cannot assign to read only property
person.city.name = 'New York'
Enter fullscreen mode Exit fullscreen mode

Now you can be sure that you create truly const objects.

P.S. I attached also version for TypeScript.

type DeepReadonly<T> = {
    readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

function deepFreeze<T>(obj: T): DeepReadonly<T> {
    Object.freeze(obj);
    Object.getOwnPropertyNames(obj).forEach(prop => {
        const value = obj[prop];
        if (typeof value === 'object' && value !== null && !Object.isFrozen(value)) {
            deepFreeze(value);
        }
    });
    return obj as DeepReadonly<T>;
}
Enter fullscreen mode Exit fullscreen mode

Subscribe to know more tips about JavaScript and TypeScript.

Top comments (0)