JavaScript Object Protection
JavaScript provides several methods to protect objects from modification. These range from preventing new properties (preventExtensions) to making an object completely immutable (freeze). Understanding these methods is essential for writing robust code.
Object.freeze()
Object.freeze() makes an object completely immutable. You cannot add, remove, or modify any properties. This is the strictest level of object protection.
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3
};
Object.freeze(config);
// None of these will work (silent fail in non-strict mode)
config.apiUrl = 'https://other.com';
config.newProp = 'test';
delete config.timeout;
console.log(config.apiUrl);
console.log(config.timeout);
console.log(config.newProp);
console.log(Object.isFrozen(config));Object.seal()
Object.seal() prevents adding or removing properties, but allows modification of existing property values. It is less restrictive than freeze.
const user = {
name: 'Alice',
age: 30,
role: 'admin'
};
Object.seal(user);
// Can modify existing properties
user.name = 'Bob';
user.age = 25;
console.log('Name: ' + user.name);
console.log('Age: ' + user.age);
// Cannot add new properties
user.email = 'bob@example.com';
console.log('Email: ' + user.email);
// Cannot delete properties
delete user.role;
console.log('Role: ' + user.role);
console.log('Sealed: ' + Object.isSealed(user));Object.preventExtensions()
Object.preventExtensions() prevents new properties from being added, but allows modification and deletion of existing properties. It is the least restrictive protection.
const settings = {
theme: 'light',
fontSize: 14
};
Object.preventExtensions(settings);
// Can modify existing properties
settings.theme = 'dark';
console.log('Theme: ' + settings.theme);
// Can delete existing properties
delete settings.fontSize;
console.log('fontSize: ' + settings.fontSize);
// Cannot add new properties
settings.language = 'en';
console.log('language: ' + settings.language);
console.log('Extensible: ' + Object.isExtensible(settings));Checking Object Protection
JavaScript provides methods to check the protection level of an object.
| Method | Add Properties | Remove Properties | Modify Values |
|---|---|---|---|
| No protection | Yes | Yes | Yes |
| preventExtensions() | No | Yes | Yes |
| seal() | No | No | Yes |
| freeze() | No | No | No |
const obj1 = { a: 1 };
const obj2 = Object.preventExtensions({ b: 2 });
const obj3 = Object.seal({ c: 3 });
const obj4 = Object.freeze({ d: 4 });
console.log('obj1 - extensible: ' + Object.isExtensible(obj1));
console.log('obj2 - extensible: ' + Object.isExtensible(obj2));
console.log('obj3 - sealed: ' + Object.isSealed(obj3));
console.log('obj4 - frozen: ' + Object.isFrozen(obj4));
// A frozen object is also sealed and non-extensible
console.log('obj4 - sealed: ' + Object.isSealed(obj4));
console.log('obj4 - extensible: ' + Object.isExtensible(obj4));Deep Freeze Pattern
Object.freeze() only does a shallow freeze. Nested objects are NOT frozen. To freeze an entire object deeply, you need a recursive deep freeze function.
const data = {
name: 'Config',
nested: {
value: 'can be changed!'
}
};
Object.freeze(data);
// Nested object is NOT frozen!
data.nested.value = 'changed!';
console.log('Nested: ' + data.nested.value);
// Deep freeze function
function deepFreeze(obj) {
Object.freeze(obj);
Object.keys(obj).forEach(function(key) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
deepFreeze(obj[key]);
}
});
return obj;
}
const deepData = deepFreeze({
name: 'Config',
nested: { value: 'immutable' }
});
deepData.nested.value = 'try to change';
console.log('Deep frozen: ' + deepData.nested.value);const vs freeze
const and Object.freeze() are different concepts. const prevents reassignment of the variable, while freeze prevents modification of the object's contents.
// const prevents reassignment
const arr = [1, 2, 3];
// arr = [4, 5, 6]; // TypeError: Assignment to constant
arr.push(4); // This works! const doesn't freeze the value
console.log('const array: ' + arr);
// freeze prevents modification
const frozenArr = Object.freeze([1, 2, 3]);
frozenArr.push(4); // Silently fails
console.log('frozen array: ' + frozenArr);
// Both together: can't reassign AND can't modify
const immutable = Object.freeze({ x: 1, y: 2 });
// immutable = {}; // TypeError (const)
immutable.x = 99; // Silently fails (freeze)
console.log('Immutable x: ' + immutable.x);