code: function recurse(object, state, callback) {
      if (!state) state = {depth:0};
      if (!state.depth) {
          state = Object.assign({},defaultState(),state);
      }
      if (typeof object !== 'object') return;
      let oPath = state.path;
      for (let key in object) {
          state.key = key;
          state.path = state.path + '/' + encodeURIComponent(jpescape(key));
          state.identityPath = state.seen.get(object[key]);
          state.identity = (typeof state.identityPath !== 'undefined');
          callback(object, key, state);
          if ((typeof object[key] === 'object') && (!state.identity)) {
              if (state.identityDetection && !Array.isArray(object[key]) && object[key] !== null) {
                  state.seen.set(object[key],state.path);
              }
              let newState = {};
              newState.parent = object;
              newState.path = state.path;
              newState.depth = state.depth ? state.depth+1 : 1;
              newState.pkey = key;
              newState.payload = state.payload;
              newState.seen = state.seen;
              newState.identity = false;
              newState.identityDetection = state.identityDetection;
              recurse(object[key], newState, callback);
          }
          state.path = oPath;
      }
  }
docs: recurses through the properties of an object, given an optional starting state
  anything you pass in state.payload is passed to the callback each time
  @param object the object to recurse through
  @param state optional starting state, can be set to null or {}
  @param callback the function which receives object,key,state on each property