Deep Copy vs JSON Stringify / JSON Parse

JavaScript performance comparison

Revision 105 of this test case created by Nicholas Mitchell

Preparation code

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>

      
<script>
Benchmark.prototype.setup = function() {
  function recursiveDeepCopy(o) {
    if (typeof o !== 'object' || !o) {
      return o;
    }
  
    let no, i;
  
    if (Array.isArray(o)) {
      no = new Array(o.length);
      for (i = 0; i < o.length; i += 1) {
        no[i] = recursiveDeepCopy(o[i]);
      }
      return no;
    }
  
    no = {};
    for (i in o) {
      if (o.hasOwnProperty(i)) {
        no[i] = recursiveDeepCopy(o[i]);
      }
    }
    return no;
  }
  
  function deepCopy(o) {
    var copy = o, k;
  
    if (o && typeof o === 'object') {
      copy = Object.prototype.toString.call(o) === '[object Array]' ? [] : {};
      for (k in o) {
        copy[k] = deepCopy(o[k]);
      }
    }
  
    return copy;
  }
  
  function deepCopy2(obj) {
    return Object.keys(obj).reduce((v, d) => Object.assign(v, {
      [d]: (obj[d].constructor === Object) ? deepCopy2(obj[d]) : obj[d]
    }), {});
  }
  
  function clone(obj) {
    if (obj == null || typeof(obj) != 'object')
      return obj;
  
    var temp = new obj.constructor();
    for (var key in obj)
      temp[key] = clone(obj[key]);
  
    return temp;
  }
  
  const deepClone = (
    obj,
    options = {
        copyGetterOnlyRoot: true,
        copyGetterSetter: true
    },
    root = true
  ) => {
    let i = undefined;
    let optionsTwo =
      (root &&
        options.copyGetterOnlyRoot && {
          copyGetterSetter: false,
          copyGetterOnlyRoot: false
        }) ||
      options;
    if (!(obj instanceof Object) || obj instanceof Function) {
      return obj;
    }
    if (Array.isArray(obj)) {
      const clone = new Array(obj.length);
      for (i = 0; i < obj.length; i++) {
        clone[i] = deepClone(obj[i], optionsTwo);
      }
      return clone;
    }
    if (obj instanceof Date) {
      return new Date(obj.getTime());
    }
    if (obj instanceof RegExp) {
      return new RegExp(obj.source);
    }
    const clone = {};
    let setter = null;
    let getter = null;
    for (i in obj) {
      if (obj.hasOwnProperty(i)) {
        if (options.copyGetterSetter) {
          setter = obj.__lookupSetter__(i);
          getter = obj.__lookupGetter__(i);
        }
        if (setter || getter) {
          if (getter) {
            clone.__defineGetter__(i, getter);
          }
          if (setter) {
            clone.__defineSetter__(i, setter);
          }
        } else {
          clone[i] = deepClone(obj[i], optionsTwo);
        }
      }
    }
    return clone;
  };
  
  var uc = {
    "list": {
      "0oVwOM": {
        "id": "0oVwOM",
        "parent": "pTlmbh",
        "name": "New node",
        "created_at": 1384289621
      },
      "aHxe8k": {
        "id": "aHxe8k",
        "parent": "Fhs2hL",
        "name": "hjkhjkhjk",
        "created_at": 1384354593
      },
      "Fhs2hL": {
        "id": "Fhs2hL",
        "parent": "root",
        "name": "test",
        "created_at": 1383403881
      },
      "HYPSgv": {
        "id": "HYPSgv",
        "parent": "0oVwOM",
        "name": "New node",
        "created_at": 1384342657
      },
      "osFIMf": {
        "id": "osFIMf",
        "parent": "root",
        "name": "New node",
        "created_at": 1384354584
      },
      "PsovXE": {
        "id": "PsovXE",
        "parent": "root",
        "name": "hjkhjkhjk",
        "created_at": 1384354589
      },
      "pTlmbh": {
        "id": "pTlmbh",
        "parent": "Fhs2hL",
        "name": "New node",
        "created_at": 1384289277
      },
      "RbXhdJ": {
        "id": "RbXhdJ",
        "parent": "root",
        "name": "empty",
        "created_at": 1384359806
      }
    },
    "maps": {
      "parent": {
        "pTlmbh": {
          "0oVwOM": {
            "id": "0oVwOM",
            "parent": "pTlmbh",
            "name": "New node",
            "created_at": 1384289621
          }
        },
        "Fhs2hL": {
          "aHxe8k": {
            "id": "aHxe8k",
            "parent": "Fhs2hL",
            "name": "hjkhjkhjk",
            "created_at": 1384354593
          },
          "pTlmbh": {
            "id": "pTlmbh",
            "parent": "Fhs2hL",
            "name": "New node",
            "created_at": 1384289277
          }
        },
        "root": {
          "Fhs2hL": {
            "id": "Fhs2hL",
            "parent": "root",
            "name": "test",
            "created_at": 1383403881
          },
          "osFIMf": {
            "id": "osFIMf",
            "parent": "root",
            "name": "New node",
            "created_at": 1384354584
          },
          "PsovXE": {
            "id": "PsovXE",
            "parent": "root",
            "name": "hjkhjkhjk",
            "created_at": 1384354589
          },
          "RbXhdJ": {
            "id": "RbXhdJ",
            "parent": "root",
            "name": "empty",
            "created_at": 1384359806
          }
        },
        "0oVwOM": {
          "HYPSgv": {
            "id": "HYPSgv",
            "parent": "0oVwOM",
            "name": "New node",
            "created_at": 1384342657
          }
        }
      },
      "path": [
        ["Fhs2hL"],
        ["Fhs2hL", "aHxe8k"],
        ["Fhs2hL", "pTlmbh"],
        ["Fhs2hL", "pTlmbh", "0oVwOM"],
        ["Fhs2hL", "pTlmbh", "0oVwOM", "HYPSgv"],
        ["osFIMf"],
        ["PsovXE"],
        ["RbXhdJ"]
      ]
    }
  };
  

};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
_.merge
var bes = _.merge(uc)
pending…
_.cloneDeep
var bes = _.cloneDeep(uc)
pending…
recursive
var bes = recursiveDeepCopy(uc);
pending…
JSON Stringify / JSON Parse
var bes = JSON.parse(JSON.stringify(uc))
pending…
Deep clone recursive
var bes = deepClone(uc,{
copyGetterSetter: false,
copyGetterOnlyRoot: false
})
pending…
Deep Copy
var bes = deepCopy(uc)
pending…

Compare results of other browsers

Revisions

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

0 Comments