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.

Freezing an Object
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.

Sealing an Object
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.

Preventing Extensions
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.

MethodAdd PropertiesRemove PropertiesModify Values
No protectionYesYesYes
preventExtensions()NoYesYes
seal()NoNoYes
freeze()NoNoNo
Checking Protection Status
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.

Shallow vs Deep Freeze
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 vs Object.freeze()
// 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);
📝 Note: In strict mode, attempting to modify a frozen or sealed object will throw a TypeError instead of silently failing. It is a best practice to use 'use strict' or ES modules (which are strict by default) when working with protected objects to catch these violations early.
Exercise:
Which method prevents adding new properties but still allows modifying existing ones?
Try it YourselfCtrl+Enter to run
Click Run to see the output here.