What is the best and most efficient way to deep clone an object in JavaScript?

January 27, 2020 1 Comment QA JavaScript Cloning Objects

1. Introduction

In every programming language sometimes there is a need to make an exact copy of one object. Copy that will be a faithful reflection of the base object, with all attributes and fields at every nesting level. In JavaScript we have several ways to make a deep clone of an object.

// our base object
var obj = {
    a: "hello",
    c: "test",
    po: 33,
    arr: [1, 2, 3, 4],
    anotherObj: {
        a: 33,
        str: "whazzup"
    }
};

2. Using JSON stringify function

var obj2 = JSON.parse(JSON.stringify(obj));

Note that this method will not work if your object contains: Dates, functions, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays or other complex types.

3. Using lodash deep clone method

var obj2 = _.cloneDeep(obj, true);

4. Angular framework comes with angular.copy function

var obj2 = angular.copy(obj);

5. Using jQuery extend function

var obj2 = $.extend(true, {}, obj);

6. Using Object.assign (this makes a shallow copy, thanks Concerned Citizen for pointing this out in comments)

var obj2 = Object.assign({}, obj);

7. Performance comparision

Now lets check the performance comparision. Javascript deep copy comparison of solutions

If you want to check this benchmark by yourself, click this link: http://jsben.ch/P8MHg

8. Conclusion

According to the benchmark test, the fastest way to deep clone an object in javascript is to use lodash deep clone function since Object.assign supports only shallow copy. Unfortunately, this is an external library, if you don't want to use one you can check below deepClone function written in vanilla JS.

function clone(item) {
    if (!item) { return item; } // null, undefined values check

    var types = [ Number, String, Boolean ], 
        result;

    // normalizing primitives if someone did new String('aaa'), or new Number('444');
    types.forEach(function(type) {
        if (item instanceof type) {
            result = type( item );
        }
    });

    if (typeof result == "undefined") {
        if (Object.prototype.toString.call( item ) === "[object Array]") {
            result = [];
            item.forEach(function(child, index, array) { 
                result[index] = clone( child );
            });
        } else if (typeof item == "object") {
            // testing that this is DOM
            if (item.nodeType && typeof item.cloneNode == "function") {
                result = item.cloneNode( true );    
            } else if (!item.prototype) { // check that this is a literal
                if (item instanceof Date) {
                    result = new Date(item);
                } else {
                    // it is an object literal
                    result = {};
                    for (var i in item) {
                        result[i] = clone( item[i] );
                    }
                }
            } else {
                // depending what you would like here,
                // just keep the reference, or create new object
                if (false && item.constructor) {
                    // would not advice to do that, reason? Read below
                    result = new item.constructor();
                } else {
                    result = item;
                }
            }
        } else {
            result = item;
        }
    }

    return result;
}
{{ message }}

{{ 'Comments are closed.' | trans }}