Cloning an Object (v100)

Revision 100 of this benchmark created on


Description

There is no quick and easy facility for cloning an object, Some people recommend using JQuery.extend others JSON.parse/stringify

http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-a-javascript-object

If you want the fastest possible clone function. I would personally anticipate the data structure of your object and write a custom clone to handle it.

Preparation HTML

<script src="http://code.jquery.com/jquery-1.5.1.js" type="text/javascript"></script>


<script>
  var oldObject = {
   a: 1,
   b: 2,
   c: 3,
   d: 4,
   e: 5,
   f: function() {
    return 6;
   },
   g: [7, 8, 9]
  };
  
  
  function clone(obj) {
   var target = {};
   for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
     target[i] = obj[i];
    }
   }
   return target;
  }
  
  Object.defineProperties(Object, {
   'extend': {
    'configurable': true,
    'enumerable': false,
    'value': function extend(what, wit) {
     var extObj, witKeys = Object.keys(wit);
  
     extObj = Object.keys(what).length ? Object.clone(what) : {};
  
     witKeys.forEach(function(key) {
      Object.defineProperty(extObj, key, Object.getOwnPropertyDescriptor(wit, key));
     });
  
     return extObj;
    },
    'writable': true
   },
   'clone': {
    'configurable': true,
    'enumerable': false,
    'value': function clone(obj) {
     return Object.extend({}, obj);
    },
    'writable': true
   }
  });

function cloneOURS(src) {
    function mixin(dest, source, copyFunc) {
        var name, s, i, empty = {};
        for (name in source){
            // the (!(name in empty) || empty[name] !== s) condition avoids copying properties in "source"
            // inherited from Object.prototype.   For example, if dest has a custom toString() method,
            // don't overwrite it with the toString() method that source inherited from Object.prototype
            s = source[name];
            if (!(name in dest) || (dest[name] !== s && (!(name in empty) || empty[name] !== s))) {
                dest[name] = copyFunc ? copyFunc(s) : s;
            }
        }
        return dest;
    }
    if (!src || typeof src != "object" || Object.prototype.toString.call(src) === "[object Function]") {
        // null, undefined, any non-object, or function
        return src;  // anything
    }
    if (src.nodeType && "cloneNode" in src) {
        // DOM Node
        return src.cloneNode(true); // Node
    }
    if (src instanceof Date) {
        // Date
        return new Date(src.getTime());  // Date
    }
    if (src instanceof RegExp) {
        // RegExp
        return new RegExp(src);   // RegExp
    }
    var r, i, l;
    if (src instanceof Array) {
        // array
        r = [];
        for (i = 0, l = src.length; i < l; ++i){
            if (i in src){
                r.push(clone(src[i]));
            }
        }
    } else {
        // generic objects
        r = src.constructor ? new src.constructor() : {};
    }
    return mixin(r, src, clone);
};

</script>

Test runner

Ready to run.

Testing in
TestOps/sec
JQuery.extend deep
var newObject = jQuery.extend(true, {}, oldObject);
ready
JSON
var newObject = JSON.parse(JSON.stringify(oldObject));
ready
JQuery.extend
var newObject = jQuery.extend({}, oldObject);
ready
simple clone function
var newObject = clone(oldObject);
ready
ES5 Object.clone
var newObject = Object.clone(oldObject);
ready
cloneOURS
var newObject = cloneOURS(oldObject);
ready

Revisions

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