Nodejs:如何克隆一个对象

如果我克隆一个数组,我使用cloneArr = arr.slice()

我想知道如何在nodejs中克隆一个对象。

对于那些没有必要压缩性能的实用程序和类,我经常作弊,只是使用JSON来执行深层复制:

 function clone(a) { return JSON.parse(JSON.stringify(a)); } 

这不是唯一的答案或最优雅的答案; 所有其他的答案都应该考虑到生产瓶颈。 但是,这是一个快速和肮脏的解决scheme,相当有效,并在大多数情况下,我会克隆简单的属性哈希值有用。

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

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

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

没有用于克隆对象的本机方法。 _.clone实现了_.clone ,它是一个浅层克隆。

 _.clone = function(obj) { return _.isArray(obj) ? obj.slice() : _.extend({}, obj); }; 

它要么切片,要么延伸。

这里是_.extend

 // extend the obj (first parameter) _.extend = function(obj) { // for each other parameter each(slice.call(arguments, 1), function(source) { // loop through all properties of the other objects for (var prop in source) { // if the property is not undefined then add it to the object. if (source[prop] !== void 0) obj[prop] = source[prop]; } }); // return the object (first parameter) return obj; }; 

扩展只是遍历所有的项目,并创build一个新的对象与其中的项目。

如果你愿意的话,你可以推出你自己的天真执行

 function clone(o) { var ret = {}; Object.keys(o).forEach(function (val) { ret[val] = o[val]; }); return ret; } 

有很好的理由避免深度克隆,因为不能克隆closures。

我曾经亲自问过一个关于deep cloning objects before的问题,我得出的结论是你不这样做。

我的build议是使用underscore ,它是浅层克隆的_.clone方法

做一个通用但有用的克隆操作是很困难的,因为应该recursion地克隆什么东西,应该只是复制什么,取决于具体的对象应该如何工作。

可能有用的东西是

 function clone(x) { if (x === null || x === undefined) return x; if (x.clone) return x.clone(); if (x.constructor == Array) { var r = []; for (var i=0,n=x.length; i<n; i++) r.push(clone(x[i])); return r; } return x; } 

在这个代码中的逻辑是

  • nullundefined情况下,只是返回相同的(特殊情况是需要的,因为这是一个错误,试图看看是否存在clone方法)
  • 对象是否有clone方法? 然后使用它
  • 是一个数组的对象? 然后做一个recursion的克隆操作
  • 否则只是返回相同的值

这个克隆函数应该允许轻松实现自定义的克隆方法…例如

 function Point(x, y) { this.x = x; this.y = y; ... } Point.prototype.clone = function() { return new Point(this.x, this.y); }; function Polygon(points, style) { this.points = points; this.style = style; ... } Polygon.prototype.clone = function() { return new Polygon(clone(this.points), this.style); }; 

在对象中,如果您知道特定数组的正确克隆操作只是浅拷贝,则可以调用values.slice()而不是clone(values)

例如,在上面的代码中,我明确要求克隆多边形对象将克隆点,但将共享相同的样式对象。 如果我想克隆样式对象,那么我可以通过clone(this.style)

对于浅拷贝,我喜欢使用reduce模式(通常在一个模块或类似的),如下所示:

 var newObject = Object.keys(original).reduce(function (obj, item) { obj[item] = original[item]; return obj; },{}); 

下面是几个选项的jsperf: http ://jsperf.com/shallow-copying

在上面的答案中没有提到Object.assign。

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

如果你在ES6上,你可以使用扩展运算符:

 let cloned = { ... source }; 

参考: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

老问题,但有一个比迄今为止build议更优雅的答案; 使用内置的utils._extend:

 var extend = require("util")._extend; var varToCopy = { test: 12345, nested: { val: 6789 } }; var copiedObject = extend({}, varToCopy); console.log(copiedObject); // outputs: // { test: 12345, nested: { val: 6789 } } 

注意第一个参数与一个空对象{}的使用 – 这表明复制的对象需要复制到一个新的对象。 如果您使用现有的对象作为第一个参数,那么第二个(以及所有后续的)参数将被深度合并复制到第一个参数variables上。

使用上面的示例variables,你也可以这样做:

 var anotherMergeVar = { foo: "bar" }; extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar); console.log(copiedObject); // outputs: // { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' } 

非常方便的实用工具,特别是在AngularJS和jQuery中用于扩展的地方。

希望这可以帮助别人; 对象引用覆盖是一个痛苦,这就解决了每一次!

你也可以使用lodash 。 它有一个克隆和cloneDeep方法。

 var _= require('lodash'); var objects = [{ 'a': 1 }, { 'b': 2 }]; var shallow = _.clone(objects); console.log(shallow[0] === objects[0]); // => true var deep = _.cloneDeep(objects); console.log(deep[0] === objects[0]); 

根据你想要用你的克隆对象做什么,你可以利用JavaScript的原型inheritance机制,并通过以下方式实现一个有点克隆的对象:

 var clonedObject = Object.create(originalObject); 

只要记住,这不是一个完整的克隆 – 好或坏。

一件好事就是你实际上没有复制对象,所以内存占用会很低。

这个方法需要记住的一些棘手的事情是,原型链中定义的属性的迭代有时会有点不同,而且原始对象的任何更改都会影响克隆的对象,除非该属性也已经设置了它自己。

我实施了一个完整的深层复制。 我相信它是一个通用克隆方法的最佳select,但它不处理循环引用。

用法示例:

 parent = {'prop_chain':3} obj = Object.create(parent) obj.a=0; obj.b=1; obj.c=2; obj2 = copy(obj) console.log(obj, obj.prop_chain) // '{'a':0, 'b':1, 'c':2} 3 console.log(obj2, obj2.prop_chain) // '{'a':0, 'b':1, 'c':2} 3 parent.prop_chain=4 obj2.a = 15 console.log(obj, obj.prop_chain) // '{'a':0, 'b':1, 'c':2} 4 console.log(obj2, obj2.prop_chain) // '{'a':15, 'b':1, 'c':2} 4 

代码本身:

这个代码复制对象与他们的原型,它也复制function(可能对某人有用)。

 function copy(obj) { // (F.prototype will hold the object prototype chain) function F() {} var newObj; if(typeof obj.clone === 'function') return obj.clone() // To copy something that is not an object, just return it: if(typeof obj !== 'object' && typeof obj !== 'function' || obj == null) return obj; if(typeof obj === 'object') { // Copy the prototype: newObj = {} var proto = Object.getPrototypeOf(obj) Object.setPrototypeOf(newObj, proto) } else { // If the object is a function the function evaluate it: var aux newObj = eval('aux='+obj.toString()) // And copy the prototype: newObj.prototype = obj.prototype } // Copy the object normal properties with a deep copy: for(var i in obj) { if(obj.hasOwnProperty(i)) { if(typeof obj[i] !== 'object') newObj[i] = obj[i] else newObj[i] = copy(obj[i]) } } return newObj; } 

有了这个副本,我找不到任何原始和复制之间的区别,除非原始的closures在其构build,所以我认为它是一个很好的实现。

我希望它有帮助

对于数组,可以使用

 var arr = [1,2,3]; var arr_2 = arr ; print ( arr_2 ); 

ARR = arr.slice(0);

 print ( arr ); arr[1]=9999; print ( arr_2 );