在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或插件阅读这里:
退房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。
他们有一个非常干净的克隆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
希望这是有帮助的。