在Node.js中克隆一个对象

在node.js中克隆对象的最好方法是什么?

例如,我想避免这样的情况:

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

该对象可能包含复杂的types作为属性,所以一个简单的(var x在obj1)不会解决。 我是否需要自己写一个recursion克隆,还是有内置的东西,我没有看到?

可能性1

低廉的深层复制:

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

可能性2(不推荐)

注意:此解决scheme现在在Node.js的文档中标记为已弃用:

util._extend()方法从来不打算在内部Node.js模块之外使用。 社区无论如何find并使用它。

它已被弃用,不应在新代码中使用。 JavaScript通过Object.assign()提供了非常类似的内置function。

原始答案

对于浅拷贝,使用Node内置的util._extend()函数。

 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 

Node的_extend函数的源代码在这里: 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; }; 

我很惊讶Object.assign没有被提及。

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

如果可用(例如Babel),则可以使用对象扩展运算符 :

 let cloned = { ... source }; 
 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; } }); 

这将定义一个可以使用的扩展方法。 代码来自这篇文章。

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

你可以使用JQuery的扩展函数:

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

还有一个Node.js插件:

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

要做到这一点没有JQuery或插件阅读这里:

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

退房underscore.js 。 它既克隆又扩展 ,还有许多其他非常有用的function。

这可能很有用: 使用带有Node.js的Underscore模块

如果不想“滚动你自己的”,有一些节点模块。 这看起来不错: https : //www.npmjs.com/package/clone

看起来像处理各种东西,包括循环引用。 从github页面:

克隆主人克隆对象,数组,Date对象和RegEx对象。 所有东西都是recursion克隆的,例如,你可以在对象中的数组中克隆date。 […]循环参考? 是的!

在NodeJS中克隆对象的最简单和最快捷的方法是使用Object.keys(obj)方法

 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] ]; } ba = 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"} 

Object.keys方法需要JavaScript 1.8.5; nodeJS v0.4.11支持这种方法

但是对于嵌套对象当然需要实现recursionfunction


其他解决scheme是使用本机JSON(在JavaScript 1.7中实现),但比前一个更慢(约10倍)

 var a = {"a": i, "b": i*i}; var b = JSON.parse(JSON.stringify(a)); ba = 0; 

Github上也有一个项目,旨在成为jQuery.extend()一个更直接的端口:

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

一个例子,从jQuery文档修改:

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

此代码也是工作原因Object.create()方法用指定的原型对象和属性创build一个新的对象。

 var obj1 = {x:5, y:5}; var obj2 = Object.create(obj1); obj2.x; //5 obj2.x = 6; obj2.x; //6 obj1.x; //5 

寻找一个真正的克隆选项,我偶然发现了ridcully的链接:

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

我修改了该页面上的解决scheme,以便附加到Object原型的function是不可枚举的。 这是我的结果:

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

希望这可以帮助别人。 请注意,有一些警告,特别是名为“克隆”的属性。 这对我很好。 我没有写任何功劳。 我再一次改变了它的定义。

还有另一个库lodash ,它具有clone和cloneDeep ,也有很多其他有用的function。

如果您正在使用咖啡脚本,那么就像下面这样简单:

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

虽然这不是一个深刻的克隆。

你也可以在NodeJS中使用SugarJS。

http://sugarjs.com/

他们有一个非常干净的克隆function: http : //sugarjs.com/api/Object/clone

没有一个答案让我满意,有几个不工作,或者只是浅层克隆,来自@ clint-harris的回答和使用JSON.parse / stringify是好的,但是很慢。 我发现了一个快速克隆的模块: https : //github.com/AlexeyKupershtokh/node-v8-clone

没有内置的方法来在node.js中对对象进行真正的复制(深层复制)。 有一些棘手的边缘情况,所以你一定要使用这个库。 我为我的simpleoo库编写了这样一个函数。 如果不需要,可以使用deepCopy函数,而不使用库中的其他任何东西(很小)。 这个函数支持克隆多种数据types,包括数组,date和正则expression式,它支持recursion引用,也可以用于构造函数具有所需参数的对象。

这里是代码:

 //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; }; 
 npm install node-v8-clone 

最快的克隆者,它从node.js打开本地克隆方法

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

您可以创build对象的原型,然后在每次要使用和更改对象时调用对象实例:

 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 

您也可以将parameter passing给对象构造函数

 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 

希望这是有帮助的。