code: function traverse (value, v) {
    var state = {}
    var visitor = v.visitor
    var seen = []
  
    /**
     * Recursively walk the value, dispatching visitor methods as values are encountered.
     *
     * @param {*} val Value
     * @param {Value|null} parent Parent value
     * @param {object} [opts] Additional options
     */
    function traverseValue (val, parent, opts) {
      var wrapper = Value(val, parent, opts)
      var enterFn = wrapper.type + 'Enter'
      var exitFn = wrapper.type + 'Exit'
      var keys
  
      if (wrapper.type === 'object' || wrapper.type === 'array') {
        if (seen.indexOf(wrapper.value) >= 0) {
          wrapper.isCircularRef = true
        }
        seen.push(wrapper.value)
      }
  
      if (wrapper.type === 'object') {
        keys = Object.keys(wrapper.value).sort()
        wrapper.length = keys.length
      }
  
      if (visitor[enterFn]) {
        visitor[enterFn](wrapper, state)
      } else if (visitor.otherEnter) {
        visitor.otherEnter(wrapper, state)
      }
  
      switch (wrapper.type) {
        case 'array':
          if (!wrapper.isCircularRef) {
            wrapper.value.forEach(function (child, i) {
              traverseValue(child, wrapper, { key: i })
            })
          }
          break
  
        case 'object':
          if (!wrapper.isCircularRef) {
            keys.forEach(function (key) {
              traverseValue(wrapper.value[key], wrapper, { key: key })
            })
          }
          break
  
        default:
          /* do nothing */
          break
      }
  
      if (visitor[exitFn]) {
        visitor[exitFn](wrapper, state)
      }
  
      if (wrapper.type === 'object' || wrapper.type === 'array') {
        seen.pop()
      }
    }
  
    if (v.pre) { v.pre.call(null, state) }
    traverseValue(value, null, null)
    if (v.post) { v.post.call(null, state) }
  }
docs: Traverse a value with a visitor object.
  
  @param {*} value Value to traverse
  @param {Visitor} visitor Visitor instance