docs: function deepFreeze(obj) {
      // if it's already frozen, don't bother going deep into it...
      if (obj === null || typeof obj === 'undefined' || typeof obj.toJS === 'function' || typeof obj !== 'object') {
          return obj;
      }
  
      // Retrieve the property names defined on obj
      let propNames = Object.getOwnPropertyNames(obj);
      let properties = {toJS: {value: mirror.bind(obj)}};
  
      if (Array.isArray(obj)) {
          // create a copy and deep freeze all entries
          obj = obj.slice(0).map(deepFreeze);
          // re-attach some important methods
          ['map', 'forEach', 'find', 'indexOf', 'filter', 'some', 'every', 'lastIndexOf', 'slice'].forEach(fn => {
              properties[fn] = {value: function () { return deepFreeze(Array.prototype[fn].apply(obj, arguments));}};
          });
      }
  
      // Freeze properties before freezing self
      for (let index = 0, prop; prop = obj[propNames[index]], index < propNames.length; index += 1) {
          // Freeze prop if it is an object
          properties[propNames[index]] = {
              enumerable: true,
              get () {
                  return deepFreeze(prop);
              },
              set (newValue) {
                  throw new Error('Cannot change property "' + propNames[index] + '" to "' + newValue + '" of an immutable object');
              }
          }
      }
  
      // Freeze self (no-op if already frozen)
      return Object.freeze(Object.create(Object.getPrototypeOf(obj), properties));
  }