Cloning an Object in Node.js

Javascriptnode.js

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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;
};

Solution 2 - Javascript

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 };

Solution 3 - Javascript

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.

Solution 4 - Javascript

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

Solution 5 - Javascript

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

Solution 6 - Javascript

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

This can be useful: https://stackoverflow.com/questions/5691901/using-the-underscore-module-with-node-js

Solution 7 - Javascript

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!

Solution 8 - Javascript

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.

Solution 9 - Javascript

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;

Solution 10 - Javascript

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

Solution 11 - Javascript

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);

Solution 12 - Javascript

Y'all suffering yet the solution is simple.

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

var obj2 = {...obj1}; // Boom

Solution 13 - Javascript

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.

Solution 14 - Javascript

You can also use SugarJS in NodeJS.

http://sugarjs.com/

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

Solution 15 - Javascript

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.

Solution 16 - Javascript

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

Solution 17 - Javascript

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;
};

Solution 18 - Javascript

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

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

const clonedObject = clone(sourceObject);

Solution 19 - Javascript

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);

Solution 20 - Javascript

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);

Solution 21 - Javascript

npm install node-v8-clone

Fastest cloner, it open native clone method from node.js

var clone = require('node-v8-clone').clone;
var newObj = clone(obj, true); //true - deep recursive clone

Solution 22 - Javascript

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

Solution 23 - Javascript

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsliftyView Question on Stackoverflow
Solution 1 - JavascriptjimboView Answer on Stackoverflow
Solution 2 - JavascriptdjanowskiView Answer on Stackoverflow
Solution 3 - JavascriptMichael DillonView Answer on Stackoverflow
Solution 4 - Javascriptuser2516109View Answer on Stackoverflow
Solution 5 - JavascriptridcullyView Answer on Stackoverflow
Solution 6 - JavascriptespView Answer on Stackoverflow
Solution 7 - JavascriptClint HarrisView Answer on Stackoverflow
Solution 8 - JavascriptzangwView Answer on Stackoverflow
Solution 9 - JavascriptnihilView Answer on Stackoverflow
Solution 10 - JavascriptHironView Answer on Stackoverflow
Solution 11 - JavascriptRandyView Answer on Stackoverflow
Solution 12 - JavascriptNgend LioView Answer on Stackoverflow
Solution 13 - JavascriptBradView Answer on Stackoverflow
Solution 14 - JavascriptPepijnView Answer on Stackoverflow
Solution 15 - JavascriptbaluptonView Answer on Stackoverflow
Solution 16 - JavascriptWispyCloudView Answer on Stackoverflow
Solution 17 - JavascriptMatt BrowneView Answer on Stackoverflow
Solution 18 - JavascriptLanil MarasingheView Answer on Stackoverflow
Solution 19 - JavascriptAndrew ChildsView Answer on Stackoverflow
Solution 20 - JavascriptElon Gomes VieiraView Answer on Stackoverflow
Solution 21 - JavascriptOleksiy ChechelView Answer on Stackoverflow
Solution 22 - JavascriptlabelleView Answer on Stackoverflow
Solution 23 - Javascriptuser3459287View Answer on Stackoverflow