lib/bind_keys.js
function bindKeys (scope, obj, def, parentNode, path) {
  var meta, key

  if (typeof obj !== 'object' || obj === null)
    throw new TypeError(
      'Invalid type of value "' + obj + '", object expected.')

  Object.defineProperty(obj, memoizedObjectKey, {
    value: {},
    configurable: true
  })

  Object.defineProperty(obj, metaKey, {
    value: {},
    configurable: true
  })

  meta = obj[metaKey]

  for (key in def) {
    meta[key] = {
      keyPath: {
        key: key,
        root: path.root,
        target: obj
      },
      activeNodes: [],
      previousValues: [],

      // Assign the current marker relevant to this object. This is in case of
      // arrays of objects.
      currentMarker: def[key][markerKey],

      valueIsArray: null
    }

    bindKey(scope, obj, def, key, parentNode)
  }
}
function bindKeys (scope, obj, def, parentNode, path) {
  var meta, key

  if (typeof obj !== 'object' || obj === null)
    throw new TypeError(
      'Invalid type of value "' + obj + '", object expected.')

  Object.defineProperty(obj, memoizedObjectKey, {
    value: {},
    configurable: true
  })

  Object.defineProperty(obj, metaKey, {
    value: {},
    configurable: true
  })

  meta = obj[metaKey]

  for (key in def) {
    meta[key] = {
      keyPath: {
        key: key,
        root: path.root,
        target: obj
      },
      activeNodes: [],
      previousValues: [],

      // Assign the current marker relevant to this object. This is in case of
      // arrays of objects.
      currentMarker: def[key][markerKey],

      valueIsArray: null
    }

    bindKey(scope, obj, def, key, parentNode)
  }
}
Define getters & setters. This function is the internal entry point to a lot
of functionality.

@param {*} [scope]
@param {Object} obj
@param {Object} def
@param {Node} parentNode - This is not the same as
`Node.prototype.parentNode`, this is the internal parent node if the key
was bound to its parent.
@param {Array} path