clone (v5)

Revision 5 of this benchmark created by polotek on


Preparation HTML

<script src="//ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>

<!-- clone function by rwaldron -->
<script src="https://raw.github.com/gist/1239728/d6f07a6f85644a2e6a5da742c5a3c25fe9e03e03/clone.js"></script>

<script>
  function clone_json(data) {
   return JSON.parse(JSON.stringify(data));
  }
  
  function clone_recursive(data) {
   var A = Array;
   if (typeof data === "object" && data !== null) {
    var out = data instanceof A ? [] : {};
    for (var key in data) {
     if (data.hasOwnProperty(key)) {
      out[key] = clone_recursive(data[key]);
     }
    }
    return out;
   }
   return data;
  }
  
  function clone_loop(dataIn) {
   var dataOut = {};
   var queue = [],
       spec = [dataOut, 'data', dataIn];
   var A = Array;
  
   do {
    var copyTo = spec[0],
        toKey = spec[1],
        theObj = spec[2];
    if (theObj !== null && typeof theObj === "object") {
     var to = copyTo[toKey] = theObj instanceof A ? [] : {};
     for (var key in theObj) {
      if (theObj.hasOwnProperty(key)) {
       queue.push([to, key, theObj[key]]);
      }
     }
    }
    else {
     copyTo[toKey] = theObj;
    }
   } while ((spec = queue.shift()));
  
   return dataOut.data;
  }
  
  function clone_recursive_create(data) {
   var A = Array;
   if (typeof data === "object" && data !== null) {
    if (data instanceof A) {
     return map(data, clone_recursive_create);
    }
    else {
     var out = Object.create(data);
     var keys = getKeys(data);
     for (var i = 0, len = keys.length; i < len; i++) {
      var key = keys[i],
          thing = out[key];
      if (thing !== null && typeof thing === "object") {
       out[key] = clone_recursive_create(thing);
      }
     }
    }
   }
   return data;
  }
  
  var cloner = {
   _clone: function _clone(obj) {
    if (obj instanceof Array) {
     var out = [];
     for (var i = 0, len = obj.length; i < len; i++) {
      var value = obj[i];
      out[i] = (value !== null && typeof value === "object") ? _clone(value) : value;
     }
    }
    else {
     var out = {};
     for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
       var value = obj[key];
       out[key] = (value !== null && typeof value === "object") ? _clone(value) : value;
      }
     }
    }
    return out;
   },
  
   clone: function(it) {
    return this._clone({
     it: it
    }).it;
   }
  };
  var cloner2 = {
   _clone: function _clone(obj) {
    if (obj instanceof Array) {
     var out = [];
     for (var i = 0, len = obj.length; i < len; i++) {
      var value = obj[i];
      out[i] = (value instanceof Object) ? _clone(value) : value;
     }
    }
    else {
     var out = {};
     for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
       var value = obj[key];
       out[key] = (value instanceof Object) ? _clone(value) : value;
      }
     }
    }
    return out;
   },
  
   clone: function(it) {
    return this._clone({
     it: it
    }).it;
   }
  };
  var cloner3 = {
   _clone: function _clone(obj) {
    var O = Object;
    if (obj instanceof Array) {
     var out = [];
     for (var i = 0, len = obj.length; i < len; i++) {
      var value = obj[i];
      out[i] = (value instanceof O) ? _clone(value) : value;
     }
    }
    else {
     var out = {};
     for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
       var value = obj[key];
       out[key] = (value instanceof O) ? _clone(value) : value;
      }
     }
    }
    return out;
   },
  
   clone: function(it) {
    return this._clone({
     it: it
    }).it;
   }
  };
  
  var getKeys = Object.keys ||
  function(obj) {
   var keys = [];
   for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
     keys.push(key);
    }
   }
   return keys;
  };
  
  
  var map = ([].map ?
  function(a, func) {
   return a.map(func);
  } : function(a, func) {
   var out = [];
   for (var i = 0, len = a.len; i < len; i++) {
    out[i] = func(a[i]);
   }
   return out;
  });
  
  var data = {
   "web-app": {
    "servlet": [{
     "servlet-name": "cofaxCDS",
     "servlet-class": "org.cofax.cds.CDSServlet",
     "init-param": {
      "configGlossary:installationAt": "Philadelphia, PA",
      "configGlossary:adminEmail": "ksm@pobox.com",
      "configGlossary:poweredBy": "Cofax",
      "configGlossary:poweredByIcon": "/images/cofax.gif",
      "configGlossary:staticPath": "/content/static",
      "templateProcessorClass": "org.cofax.WysiwygTemplate",
      "templateLoaderClass": "org.cofax.FilesTemplateLoader",
      "templatePath": "templates",
      "templateOverridePath": "",
      "defaultListTemplate": "listTemplate.htm",
      "defaultFileTemplate": "articleTemplate.htm",
      "useJSP": false,
      "jspListTemplate": "listTemplate.jsp",
      "jspFileTemplate": "articleTemplate.jsp",
      "cachePackageTagsTrack": 200,
      "cachePackageTagsStore": 200,
      "cachePackageTagsRefresh": 60,
      "cacheTemplatesTrack": 100,
      "cacheTemplatesStore": 50,
      "cacheTemplatesRefresh": 15,
      "cachePagesTrack": 200,
      "cachePagesStore": 100,
      "cachePagesRefresh": 10,
      "cachePagesDirtyRead": 10,
      "searchEngineListTemplate": "forSearchEnginesList.htm",
      "searchEngineFileTemplate": "forSearchEngines.htm",
      "searchEngineRobotsDb": "WEB-INF/robots.db",
      "useDataStore": true,
      "dataStoreClass": "org.cofax.SqlDataStore",
      "redirectionClass": "org.cofax.SqlRedirection",
      "dataStoreName": "cofax",
      "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
      "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
      "dataStoreUser": "sa",
      "dataStorePassword": "dataStoreTestQuery",
      "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
      "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
      "dataStoreInitConns": 10,
      "dataStoreMaxConns": 100,
      "dataStoreConnUsageLimit": 100,
      "dataStoreLogLevel": "debug",
      "maxUrlLength": 500
     }
    },
    {
     "servlet-name": "cofaxEmail",
     "servlet-class": "org.cofax.cds.EmailServlet",
     "init-param": {
      "mailHost": "mail1",
      "mailHostOverride": "mail2"
     }
    },
    {
     "servlet-name": "cofaxAdmin",
     "servlet-class": "org.cofax.cds.AdminServlet"
    },
  
    {
     "servlet-name": "fileServlet",
     "servlet-class": "org.cofax.cds.FileServlet"
    },
    {
     "servlet-name": "cofaxTools",
     "servlet-class": "org.cofax.cms.CofaxToolsServlet",
     "init-param": {
      "templatePath": "toolstemplates/",
      "log": 1,
      "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
      "logMaxSize": "",
      "dataLog": 1,
      "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
      "dataLogMaxSize": "",
      "removePageCache": "/content/admin/remove?cache=pages&id=",
      "removeTemplateCache": "/content/admin/remove?cache=templates&id=",
      "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
      "lookInContext": 1,
      "adminGroupID": 4,
      "betaServer": true
     }
    }],
    "servlet-mapping": {
     "cofaxCDS": "/",
     "cofaxEmail": "/cofaxutil/aemail/*",
     "cofaxAdmin": "/admin/*",
     "fileServlet": "/static/*",
     "cofaxTools": "/tools/*"
    },
  
    "taglib": {
     "taglib-uri": "cofax.tld",
     "taglib-location": "/WEB-INF/tlds/cofax.tld"
    }
   }
  };
  
  var data2 = [{
   "id": "0001",
   "type": "donut",
   "name": "Cake",
   "ppu": 0.55,
   "batters": {
    "batter": [{
     "id": "1001",
     "type": "Regular"
    },
    {
     "id": "1002",
     "type": "Chocolate"
    },
    {
     "id": "1003",
     "type": "Blueberry"
    },
    {
     "id": "1004",
     "type": "Devil's Food"
    }]
   },
   "topping": [{
    "id": "5001",
    "type": "None"
   },
   {
    "id": "5002",
    "type": "Glazed"
   },
   {
    "id": "5005",
    "type": "Sugar"
   },
   {
    "id": "5007",
    "type": "Powdered Sugar"
   },
   {
    "id": "5006",
    "type": "Chocolate with Sprinkles"
   },
   {
    "id": "5003",
    "type": "Chocolate"
   },
   {
    "id": "5004",
    "type": "Maple"
   }]
  },
  {
   "id": "0002",
   "type": "donut",
   "name": "Raised",
   "ppu": 0.55,
   "batters": {
    "batter": [{
     "id": "1001",
     "type": "Regular"
    }]
   },
   "topping": [{
    "id": "5001",
    "type": "None"
   },
   {
    "id": "5002",
    "type": "Glazed"
   },
   {
    "id": "5005",
    "type": "Sugar"
   },
   {
    "id": "5003",
    "type": "Chocolate"
   },
   {
    "id": "5004",
    "type": "Maple"
   }]
  },
  {
   "id": "0003",
   "type": "donut",
   "name": "Old Fashioned",
   "ppu": 0.55,
   "batters": {
    "batter": [{
     "id": "1001",
     "type": "Regular"
    },
    {
     "id": "1002",
     "type": "Chocolate"
    }]
   },
   "topping": [{
    "id": "5001",
    "type": "None"
   },
   {
    "id": "5002",
    "type": "Glazed"
   },
   {
    "id": "5003",
    "type": "Chocolate"
   },
   {
    "id": "5004",
    "type": "Maple"
   }]
  }];
</script>

Test runner

Ready to run.

Testing in
TestOps/sec
clone w/JSON
clone_json(data);
clone_json(data2);
ready
clone traditional / recursive
clone_recursive(data);
clone_recursive(data2);
ready
clone traditional / looped
clone_loop(data);
clone_loop(data2);
ready
clone w/Object.create() / recursice
clone_recursive_create(data);
clone_recursive_create(data2);
ready
clone / early iteration
cloner.clone(data);
cloner.clone(data2);
ready
clone / early iteration w/instanceof
cloner2.clone(data);
cloner2.clone(data2);
ready
clone / early iteration w/instanceof + local reference to Object
cloner3.clone(data);
cloner3.clone(data2);
ready
clone
clone(data);
clone(data2);
ready

Revisions

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