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'
}
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 }
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' }
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'
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' } }
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'
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>;
}
Subscribe to know more tips about JavaScript and TypeScript.
Top comments (0)