code: function walkImpl(root, traversalStrategy, beforeFunc, afterFunc, context, collectResults) {
    return (function _walk(stack, value, key, parent) {
      if (isObject(value) && stack.indexOf(value) >= 0)
        throw new TypeError('A cycle was detected at ' + value);
  
      if (beforeFunc) {
        var result = beforeFunc.call(context, value, key, parent);
        if (result === stopWalk) return stopWalk;
        if (result === stopRecursion) return;  // eslint-disable-line consistent-return
      }
  
      var subResults;
      var target = traversalStrategy(value);
  
      if (isObject(target) && Object.keys(target).length > 0) {
        // Collect results from subtrees in the same shape as the target.
        if (collectResults) subResults = Array.isArray(target) ? [] : {};
  
        var ok = each(target, function(obj, key) {
          var result = _walk(copyAndPush(stack, value), obj, key, value);
          if (result === stopWalk) return false;
          if (subResults) subResults[key] = result;
        });
        if (!ok) return stopWalk;
      }
      if (afterFunc) return afterFunc.call(context, value, key, parent, subResults);
    })([], root);
  }
docs: Walk the tree recursively beginning with `root`, calling `beforeFunc` before visiting an objects descendents, and `afterFunc` afterwards. If `collectResults` is true, the last argument to `afterFunc` will be a collection of the results of walking the node's subtrees.