238

What is the best way to clone an object in node.js

e.g. I want to avoid the situation where:

var obj1 = {x: 5, y:5};
var obj2 = obj1;
obj2.x = 6;
console.log(obj1.x); // logs 6

The object may well contain complex types as attributes, so a simple for(var x in obj1) wouldn't solve. Do I need to write a recursive clone myself or is there something built in that I'm not seeing?

slifty
  • 13,062
  • 13
  • 71
  • 109
  • 24
    1. `npm install underscore` 2. `var _ = require('underscore')` 3. `_.clone(objToClone)`; – Samuel Katz Jul 24 '12 at 18:50
  • 4
    Note that in in @SalmanPK's comment above, this is a **shallow** clone. so it will work for slifty's example, but if there are nested arrays or objects, they'll be references. :/ – Jesse Aug 07 '12 at 01:21
  • 1
    I found this article very helpful: http://heyjavascript.com/4-creative-ways-to-clone-objects/ – Jordan Hudson Mar 17 '13 at 15:15
  • 3
    @Jordan Hudson - Very nice use of JSON in the second example. var newObj = JSON.parse(JSON.stringify(oldObj)); //Now newObj is a clone. Only problem is that stringify will not work on recursive reference so need to be careful. – Kfir Erez Jul 18 '13 at 15:42

21 Answers21

332

Possibility 1

Low-frills deep copy:

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

Possibility 2 (deprecated)

Attention: This solution is now marked as deprecated in the documentation of Node.js:

The util._extend() method was never intended to be used outside of internal Node.js modules. The community found and used it anyway.

It is deprecated and should not be used in new code. JavaScript comes with very similar built-in functionality through Object.assign().

Original answer::

For a shallow copy, use Node's built-in util._extend() function.

var extend = require('util')._extend;

var obj1 = {x: 5, y:5};
var obj2 = extend({}, obj1);
obj2.x = 6;
console.log(obj1.x); // still logs 5

Source code of Node's _extend function is in here: https://github.com/joyent/node/blob/master/lib/util.js

exports._extend = function(origin, add) {
  // Don't do anything if add isn't an object
  if (!add || typeof add !== 'object') return origin;

  var keys = Object.keys(add);
  var i = keys.length;
  while (i--) {
    origin[keys[i]] = add[keys[i]];
  }
  return origin;
};
Community
  • 1
  • 1
jimbo
  • 11,004
  • 6
  • 29
  • 46
  • 5
    The question specifically called for a recursive clone. This is a shallow clone. – Benjamin Atkin Jul 15 '13 at 21:13
  • 28
    Isn't a name like `_*` supposed to mean it's a private method and should not be relied upon? – Fluffy Jul 27 '13 at 14:11
  • 7
    Every JavaScript project of any size has one or more implementations of extend(), and Node is no exception. The Node.js core makes extensive use of this function. To quote Isaacs, ["It's not going anywhere any time soon."](https://github.com/joyent/node/pull/4834#issuecomment-13981250) – jimbo Aug 02 '13 at 21:15
  • 2
    worked perfectly for me. much better than messing about with Object prototype imo – Michael Dausmann Sep 21 '13 at 12:19
  • 1
    I *wish* this worked, it would have been awesome. But you have not avoided the pass-by-reference problem in which the author initially asked. – netpoetica Oct 07 '13 at 13:06
  • @netpoetica: It worked for me, nested objects were not copied as references. Just commenting for anyone else who reads this comments... – Aaron Storck May 29 '14 at 00:26
  • 1
    @AaronStorck, I think you are mistaken. Consider the following code: `var obj = {arr:[1]}; var copy = _extend(obj); obj.arr.push(2);`. At the end of this code, both `obj` and `copy` contain the array `[1,2]`, not just `copy` as would be the case with a real clone. – Matt Browne May 31 '14 at 01:00
  • Properly deep-copying an object is a little more involved; I included such a function in my [simpleoo](https://github.com/mbrowne/simpleoo.js) library, and I also posted the function here: http://stackoverflow.com/a/13333781/560114 – Matt Browne May 31 '14 at 01:03
  • 1
    Originally my answer lacked a deep-copy option. So I added one that I use frequently. – jimbo Jun 01 '14 at 08:17
  • 13
    This is the WRONG answer. As per node's documentation: https://nodejs.org/api/util.html#util_util_extend_obj _The `util._extend()` method was never intended to be used outside of internal Node.js modules. The community found and used it anyway._ _**It is deprecated and should not be used in new code.** JavaScript comes with very similar built-in functionality through `Object.assign().`_ – Jordie Jun 28 '16 at 00:57
  • Using JSON will fail, incase the object contains ANSI escape codes. – Tanel Tammik Jul 04 '16 at 19:21
  • This merges the add keys in to the origin object. It still returns the same updated origin object. How is that a clone? – Phil Feb 23 '17 at 16:22
  • @Phil_1984_ Typical use of `_extend()` is to pass a new empty object that gets returned. This becomes the shallow clone. You can also use `_extend()` just to copy properties. – jimbo Feb 26 '17 at 17:16
  • This is just my opinion, but rather than augmenting the "typical pattern" of `_extend` for something similar but semantically different from extending, wouldn't it be better to write e.g. `exports._clone = function(toClone) { return exports._extend({}, toClone); }` It just seems like you are advocating using an axe to hammer in a nail. – Phil Feb 27 '17 at 19:12
  • The `var obj2 = JSON.parse(JSON.stringify(obj1));` solution was perfect for my need. Thanks for sharing this. – robert arles Jul 06 '17 at 22:23
  • JSON method is the right way even if deprecated. Assign is just for shallow clone which is a bad way. [Warning for Deep Clone](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Deep_Clone). If the object can be stringified, it is better to stick with `json`. – ar2015 Mar 07 '18 at 23:26
  • Circular Reference Error. Object.assign({}, source) is the best solution – Guilherme Ferreira Mar 09 '18 at 23:46
307

I'm surprised Object.assign hasn't been mentioned.

let cloned = Object.assign({}, source);

If available (e.g. Babel), you can use the object spread operator:

let cloned = { ... source };
djanowski
  • 5,610
  • 1
  • 27
  • 17
  • 2
    this is a much better solution than having to import a third-party library or use the imperfect JSON workaround. Thanks! – Neil S Feb 23 '16 at 01:03
  • 93
    this is a shallow copy – Jordan Davidson Feb 25 '16 at 23:09
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign Cloning an object – István Pató Apr 04 '16 at 15:43
  • If anyone's wondering, this is how you clone an array: clone = arr.slice(0) – Tanel Tammik Jul 04 '16 at 19:23
  • 16
    Warning for Deep Clone, For deep clone still need to use other alternatives. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Deep_Clone – gsalgadotoledo Jul 24 '16 at 14:20
  • This definitely is the most elegant answer, thank you very much! – siyb Nov 21 '16 at 09:40
  • 1
    From what I can tell the object spread operator is not an ES6 thing but instead a stage 3 proposal. which means you can use it with babel but not without from what I understand. https://github.com/tc39/proposal-object-rest-spread#status-of-this-proposal – macdja38 Apr 08 '17 at 08:55
  • @macdja38 You're right, I updated my answer, thank you. – djanowski Jul 05 '17 at 15:15
  • Object.assign does a shallow copy. look at this article: https://scotch.io/bar-talk/copying-objects-in-javascript – Ehsan Shekari Jan 05 '19 at 05:39
  • Checking with node10: it does not sound like a cloned object. Using `const a = { a: 1, b: 2 }; const b = Object.assign(a, { b: 42 }); console.log(a); console.log(b);`. Both `b` and `a` would include my modification. – SYN Nov 28 '19 at 13:36
  • Furthermore, assign() will copy functions not JSON trick. let o= Object.assign({}, {logit:(m)=>console.log(m)}); console.log(o); console.log(JSON.parse(JSON.stringify(o))); – Martin P. Dec 15 '20 at 18:46
  • Much better answer than the accepted one. – phette23 Feb 25 '23 at 06:17
24
Object.defineProperty(Object.prototype, "extend", {
    enumerable: false,
    value: function(from) {
        var props = Object.getOwnPropertyNames(from);
        var dest = this;
        props.forEach(function(name) {
            if (name in dest) {
                var destination = Object.getOwnPropertyDescriptor(from, name);
                Object.defineProperty(dest, name, destination);
            }
        });
        return this;
    }
});

This will define an extend method that you can use. Code comes from this article.

Michael Dillon
  • 31,973
  • 6
  • 70
  • 106
  • I don't see how this is supposed to work. It modifies the original Object! How am I supposed to use this function to get a clone of an object? Can you add some usage code here? After reading your post and the blog post, I still can't figure out how this is intended to be used for cloning an object. – Brad Mar 28 '12 at 03:30
  • 3
    does this really work? "if (name in dest)" - will only change the property if it already exists in dest. it should be negated. – memical Mar 30 '12 at 14:14
  • 8
    Isn't modifying Object.prototype supposed to be verboten? Also that article link is broken. – Daniel Schaffer Oct 09 '12 at 04:08
  • Just tried the article link and it works for me. Maybe it was a network blip when you tried it. – Michael Dillon Oct 09 '12 at 15:14
  • Based on a number of comments, I've updated the answer to include a variant that does not add to object's prototype. – Shamasis Bhattacharya Jul 31 '14 at 11:14
20
var obj2 = JSON.parse(JSON.stringify(obj1));
likeitlikeit
  • 5,563
  • 5
  • 42
  • 56
user2516109
  • 225
  • 2
  • 2
  • 7
    This was already suggested in [this existing answer](http://stackoverflow.com/a/7131327/447356) no point repeating it. – Shadow The GPT Wizard Jun 24 '13 at 12:15
  • 1
    @ShadowWizard these are different methods. This one simply converts to json and back to object, while linked answer uses `Object.keys()` to iterate through object – mente Oct 16 '13 at 11:21
  • 2
    This answer is wrong. JSON.stringify takes a date object and reduces it to a string, and then after parsing it leaves it as a string so it mutates the state of your object leaving you with a different object than initially in case of dates. – twboc Jan 17 '20 at 08:10
  • 1
    Further to @twboc, object properties that are explicitly undefined will not be copied using this method. – storsoc Apr 19 '22 at 17:49
13

You can use the extend function from JQuery:

var newClone= jQuery.extend({}, oldObject);  
var deepClone = jQuery.extend(true, {}, oldObject); 

There is a Node.js Plugin too:

https://github.com/shimondoodkin/nodejs-clone-extend

To do it without JQuery or Plugin read this here:

http://my.opera.com/GreyWyvern/blog/show.dml/1725165

David Tang
  • 92,262
  • 30
  • 167
  • 149
ridcully
  • 163
  • 2
12

Check out underscore.js. It has both clone and extend and many other very useful functions.

This can be useful: Using the Underscore module with Node.js

Community
  • 1
  • 1
esp
  • 7,314
  • 6
  • 49
  • 79
9

There are some Node modules out there if don't want to "roll your own". This one looks good: https://www.npmjs.com/package/clone

Looks like it handles all kinds of stuff, including circular references. From the github page:

clone masters cloning objects, arrays, Date objects, and RegEx objects. Everything is cloned recursively, so that you can clone dates in arrays in objects, for example. [...] Circular references? Yep!

pvorb
  • 7,157
  • 7
  • 47
  • 74
clint
  • 14,402
  • 12
  • 70
  • 79
7

There is another library lodash, it has clone and cloneDeep.

clone will clone your object but not create a new instance for non-primitive values, instead it will use the referrence to the original object

cloneDeep will create literally new objects without having any referrence to the original object, so it more safe when you have to change the object afterwards.

Aditya Kresna Permana
  • 11,869
  • 8
  • 42
  • 48
zangw
  • 43,869
  • 19
  • 177
  • 214
7

This code is also work cause The Object.create() method creates a new object with the specified prototype object and properties.

var obj1 = {x:5, y:5};

var obj2 = Object.create(obj1);

obj2.x; //5
obj2.x = 6;
obj2.x; //6

obj1.x; //5
Hiron
  • 141
  • 1
  • 6
5

Simple and the fastest way to clone an Object in NodeJS is to use Object.keys( obj ) method

var a = {"a": "a11", "b": "avc"};
var b;

for(var keys = Object.keys(a), l = keys.length; l; --l)
{
   b[ keys[l-1] ] = a[ keys[l-1] ];
}
b.a = 0;

console.log("a: " + JSON.stringify(a)); // LOG: a: {"a":"a11","b":"avc"} 
console.log("b: " + JSON.stringify(b)); // LOG: b: {"a":0,"b":"avc"}

The method Object.keys requires JavaScript 1.8.5; nodeJS v0.4.11 supports this method

but of course for nested objects need to implement recursive func


Other solution is to use native JSON (Implemented in JavaScript 1.7), but it's much slower (~10 times slower) than previous one

var a = {"a": i, "b": i*i};
var b = JSON.parse(JSON.stringify(a));
b.a = 0;
nihil
  • 59
  • 1
  • 1
5

There is also a project on Github that aims to be a more direct port of the jQuery.extend():

https://github.com/dreamerslab/node.extend

An example, modified from the jQuery docs:

var extend = require('node.extend');

var object1 = {
    apple: 0,
    banana: {
        weight: 52,
        price: 100
    },
    cherry: 97
};

var object2 = {
    banana: {
        price: 200
    },
    durian: 100
};

var merged = extend(object1, object2);
Randy
  • 445
  • 5
  • 9
4

Looking for a true clone option, I stumbled across ridcully's link to here:

http://my.opera.com/GreyWyvern/blog/show.dml/1725165

I modified the solution on that page so that the function attached to the Object prototype is not enumerable. Here is my result:

Object.defineProperty(Object.prototype, 'clone', {
    enumerable: false,
    value: function() {
        var newObj = (this instanceof Array) ? [] : {};
        for (i in this) {
        if (i == 'clone') continue;
            if (this[i] && typeof this[i] == "object") {
                newObj[i] = this[i].clone();
            } else newObj[i] = this[i]
        } return newObj;
    }
});

Hopefully this helps someone else as well. Note that there are some caveats... particularly with properties named "clone". This works well for me. I don't take any credit for writing it. Again, I only changed how it was being defined.

Brad
  • 159,648
  • 54
  • 349
  • 530
1

You can also use SugarJS in NodeJS.

http://sugarjs.com/

They have a very clean clone feature: http://sugarjs.com/api/Object/clone

Pepijn
  • 1,204
  • 1
  • 11
  • 25
0

None of the answers satisfied me, several don't work or are just shallow clones, answers from @clint-harris and using JSON.parse/stringify are good but quite slow. I found a module that does deep cloning fast: https://github.com/AlexeyKupershtokh/node-v8-clone

WispyCloud
  • 4,140
  • 1
  • 28
  • 31
0

There is no built-in way to do a real clone (deep copy) of an object in node.js. There are some tricky edge cases so you should definitely use a library for this. I wrote such a function for my simpleoo library. You can use the deepCopy function without using anything else from the library (which is quite small) if you don't need it. This function supports cloning multiple data types, including arrays, dates, and regular expressions, it supports recursive references, and it also works with objects whose constructor functions have required parameters.

Here is the code:

//If Object.create isn't already defined, we just do the simple shim, without the second argument,
//since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

/**
 * Deep copy an object (make copies of all its object properties, sub-properties, etc.)
 * An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
 * that doesn't break if the constructor has required parameters
 * 
 * It also borrows some code from http://stackoverflow.com/a/11621004/560114
 */ 
function deepCopy = function deepCopy(src, /* INTERNAL */ _visited) {
    if(src == null || typeof(src) !== 'object'){
        return src;
    }

    // Initialize the visited objects array if needed
    // This is used to detect cyclic references
    if (_visited == undefined){
        _visited = [];
    }
    // Ensure src has not already been visited
    else {
        var i, len = _visited.length;
        for (i = 0; i < len; i++) {
            // If src was already visited, don't try to copy it, just return the reference
            if (src === _visited[i]) {
                return src;
            }
        }
    }

    // Add this object to the visited array
    _visited.push(src);

    //Honor native/custom clone methods
    if(typeof src.clone == 'function'){
        return src.clone(true);
    }

    //Special cases:
    //Array
    if (Object.prototype.toString.call(src) == '[object Array]') {
        //[].slice(0) would soft clone
        ret = src.slice();
        var i = ret.length;
        while (i--){
            ret[i] = deepCopy(ret[i], _visited);
        }
        return ret;
    }
    //Date
    if (src instanceof Date) {
        return new Date(src.getTime());
    }
    //RegExp
    if (src instanceof RegExp) {
        return new RegExp(src);
    }
    //DOM Element
    if (src.nodeType && typeof src.cloneNode == 'function') {
        return src.cloneNode(true);
    }

    //If we've reached here, we have a regular object, array, or function

    //make sure the returned object has the same prototype as the original
    var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
    if (!proto) {
        proto = src.constructor.prototype; //this line would probably only be reached by very old browsers 
    }
    var ret = object_create(proto);

    for(var key in src){
        //Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
        //For an example of how this could be modified to do so, see the singleMixin() function
        ret[key] = deepCopy(src[key], _visited);
    }
    return ret;
};
Matt Browne
  • 12,169
  • 4
  • 59
  • 75
0

You can also use this clone library to deep clone objects.

 npm install --save clone
const clone = require('clone');

const clonedObject = clone(sourceObject);

Lanil Marasinghe
  • 2,785
  • 24
  • 24
0

If you're working with ordinary objects and arrays, and don't care about cloning functions or recursive references, here's a simple deepClone implementation which works on ordinary objects, arrays, strings, numbers, regex, dates, etc.

// Simple Deep Clone
// Does not clone functions or handle recursive references.
function deepClone(original) {
  if (original instanceof RegExp) {
    return new RegExp(original);
  } else if (original instanceof Date) {
    return new Date(original.getTime());
  } else if (Array.isArray(original)) {
    return original.map(deepClone);
  } else if (typeof original === 'object' && original !== null) {
    const clone = {};
    Object.keys(original).forEach(k => {
      clone[k] = deepClone(original[k]);
    });
    return clone;
  }
  return original;
}

// Usage:

const obj = { n: 1, a: [ { a: 1 }, { a: 2 } ], d: new Date(), s: 'foo' };
const clone = deepClone(obj);
Andrew Childs
  • 2,895
  • 1
  • 19
  • 17
0

Good article about this problem: https://www.samanthaming.com/tidbits/70-3-ways-to-clone-objects/

var obj1 = {x: 5, y:5};
var obj2 = Object.assign({}, obj1 );
    
obj2  = {z: 10};
    
console.log(obj1);
console.log(obj2);
-1

Another solution is to encapsulate directly in the new variable using: obj1= {...obj2}

labelle
  • 420
  • 4
  • 19
-1

If you're using coffee-script, it's as easy as:

newObject = {}
newObject[key] = value  for own key,value of oldObject

Though this isn't a deep clone.

balupton
  • 47,113
  • 32
  • 131
  • 182
-2

You can prototype object and then call object instance every time you want to use and change object:

function object () {
  this.x = 5;
  this.y = 5;
}
var obj1 = new object();
var obj2 = new object();
obj2.x = 6;
console.log(obj1.x); //logs 5

You can also pass arguments to object constructor

function object (x, y) {
   this.x = x;
   this.y = y;
}
var obj1 = new object(5, 5);
var obj2 = new object(6, 6);
console.log(obj1.x); //logs 5
console.log(obj2.x); //logs 6

Hope this is helpful.

user3459287
  • 95
  • 1
  • 2