Javascript Object.freeze

by horhey

JavaScript

var obj = {
  prop: function (){},
  foo: "bar"
};

// New properties may be added, existing properties may be changed or removed
obj.foo = "baz";
obj.lumpy = "woof";
delete obj.prop;

var o = Object.freeze(obj);

console.log(Object.isFrozen(obj) === true);

// Now any changes will fail
obj.foo = "quux"; // silently does nothing
obj.quaxxor = "the friendly duck"; // silently doesn't add the property

// ...and in strict mode such attempts will throw TypeErrors
function fail() {
    
    "use strict";    
    
    try {
        
        obj.foo = "sparky"; // throws a TypeError
        delete obj.quaxxor; // throws a TypeError
        obj.sparky = "arf"; // throws a TypeError
        // Attempted changes through Object.defineProperty will also throw
        Object.defineProperty(obj, "ohai", { value: 17 }); // throws a TypeError
        Object.defineProperty(obj, "foo", { value: "eit" }); // throws a TypeError   
        
    } catch(e) {
        
        console.log(e);
        
    }
    
}

fail();

obj = {
  internal : {}
};

Object.freeze(obj);
obj.internal.a = "aValue";

console.log(obj.internal.a) // "aValue"

// To make obj fully immutable, freeze each object in obj.
// To do so, we use this function.

function deepFreeze (o) {
    
  var prop, propKey;
    
  Object.freeze(o); // First freeze the object.
    
  for (propKey in o) {
      
    prop = o[propKey];
      
    if (!o.hasOwnProperty(propKey) || !(typeof prop === "object") || Object.isFrozen(prop)) {
        
      // If the object is on the prototype, not an object, or is already frozen, 
      // skip it. Note that this might leave an unfrozen reference somewhere in the
      // object if there is an already frozen object containing an unfrozen object.
      continue;
        
    }

    deepFreeze(prop); // Recursively call deepFreeze.
      
  }
    
}

var obj2 = {
  internal : {}
};

deepFreeze(obj2);
obj2.internal.a = "anotherValue";
console.log(obj2.internal.a); // undefined