Clone an object (v6)

Revision 6 of this benchmark created by herby on


Description

Recursive vs Iterative vs JSON.stringify/decode vs JSON replacer

Setup

function clone_recursive(object) {
      var result = {};
      for (var key in object) {
        var value = object[key];
        if (typeof value === 'object') {
          result[key] = clone_recursive(value);
        } else {
          result[key] = value;
        }
      }
      return result;
    }
    
    function clone_iterative(object) {
      var result = {};
      var stack = [result, object];
      var curr, base;
      while (curr = stack.pop()) {
        var base = stack.pop();
        for (var key in curr) {
          var value = curr[key];
          if (typeof value === 'object') {
            stack.push(base[key] = {});
            stack.push(value)
          } else {
            base[key] = value;
          }
        }
      }
      return result;
    }
    
    function clone_iterative_linkedList(object) {
      var result = {};
      var item = {
        base: result,
        value: object
      };
      var last = item;
      do {
        var current = item.value;
        var base = item.base;
        for (var key in current) {
          var value = current[key];
          if (typeof value === 'object') {
            var resultValue = base[key] = {};
            last.next = {
              base: resultValue,
              value: value
            };
            last = last.next;
          } else {
            base[key] = value;
          }
        }
      } while (item = item.next);
      return result;
    }
    
    function clone_JSON(o) {
      return JSON.parse(JSON.stringify(o));
    }
    
    function clone_JSON_replacer(x) {
      var r = {},
          lastSrc, lastDst = r,
          stack = [],
          v;
    
      function replacer(key, value) {
        while (this !== lastSrc && stack.length) {
          lastDst = stack.pop();
          lastSrc = stack.pop();
        }
        if (typeof value === "object") {
          stack.push(lastSrc, lastDst);
          lastDst[key] = v = new value.constructor;
          lastDst = v;
          lastSrc = value;
          return value;
        } else {
          lastDst[key] = value;
          return undefined;
        }
      }
      JSON.stringify(x, replacer);
      return r[""];
    }
    
    function makeDeepObject() {
      var root = {};
      var current = root;
      for (var i = 33, max = 136; i < max; i++) {
        var key = String.fromCharCode(i);
        var newObject = {};
        for (var j = 0; j < 25; j++) {
          newObject['a' + j] = {
            x: 1
          };
        }
        current[key] = newObject;
        for (; j < 50; j++) {
          newObject['z' + j] = {
            y: 2
          };
        }
        current = newObject;
      }
      return root;
    }
    
    var mock = makeDeepObject();

Test runner

Ready to run.

Testing in
TestOps/sec
Recursive
clone_recursive(mock)
ready
Iterative: Array
clone_iterative(mock)
ready
Iterative: linkedList
clone_iterative_linkedList(mock)
ready
JSON
clone_JSON(mock)
ready
JSON replacer
clone_JSON_replacer(mock)
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.