Node Module Walk-Through: Deep Freeze

February 23, 2016

Deep freeze is a great module from the prolific Substack. Before we get into how it works, let’s talk about what it is.

According to the readme, deep freeze is used to:

recursively Object.freeze() objects

Object.freeze is a built in JavaScript method that allows you to “freeze” an object. According to the docs that means:

It prevents new properties from being added to it; prevents existing properties from being removed; and prevents existing properties, or their enumerability, configurability, or writability, from being changed.

Let’s take a look at what this means.

var obj = {
  foo: 'foo',
  bar: 'bar'
};

obj.baz = 'baz';

console.log(obj);

// Logs
// [object Object] {
//   bar: "bar",
//   baz: "baz",
//   foo: "foo"
// }

As most of you probably know, you can set new properties on an object or change the existing properties at any time. This is what Object.freeze() prevents. Check out the following example:

var obj = {
  foo: 'foo',
  bar: 'bar'
};

Object.freeze(obj);

obj.baz = 'baz'; // Fails silently

console.log(obj);

// Logs
// [object Object] {
//   bar: "bar",
//   foo: "foo"
// }

Now we can see that with Object.freeze you can no longer change or add properties. However, Objects that are frozen aren’t quite immutable. Let’s see another example:

var obj = {
  foo: 'foo',
  bar: 'bar',
  baz: {
    foo2: 'foo2'
  }
};

Object.freeze(obj);

obj.baz = 'baz'; // Won't work

obj.baz.bar2 = 'bar2'; // Will work

console.log(obj);

// Logs
// [object Object] {
//   bar: "bar",
//   baz: [object Object] {
//     bar2: "bar2", // Oh no!
//     foo2: "foo2"
//   },
//   foo: "foo"
// }

This is where Deep Freeze comes in! It will freeze your object and any objects declared as properties recursively down the three of your object.

The Code

module.exports = function deepFreeze (o) {
  Object.freeze(o);

  Object.getOwnPropertyNames(o).forEach(function (prop) {
    if (o.hasOwnProperty(prop)
    && o[prop] !== null
    && (typeof o[prop] === "object" || typeof o[prop] === "function")
    && !Object.isFrozen(o[prop])) {
      deepFreeze(o[prop]);
    }
  });
  
  return o;
};

Let’s walk through it line by line!

  1. Module exports for Node.js imports
  2. Take in the first object ( named “o” ) and freeze it
  3. A blank line!
  4. Get each property on the object and iterate through them
  5. If the property belongs to the object ( not the prototype )
  6. Also if the property is not null
  7. Also if the property is “object” type or “function” type
  8. And lastly, if the property isn’t already frozen
  9. Then, run deep freeze on it and all of its properties