在node.js中克隆对象的最佳方法是什么
例如,我想避免以下情况:
var obj1 = {x: 5, y:5};
var obj2 = obj1;
obj2.x = 6;
console.log(obj1.x); // logs 6
该对象很可能包含复杂的类型作为属性,因此无法解决简单的for(obj1中的var x)。我需要自己编写一个递归克隆吗,还是内置了一些我看不到的东西?
在node.js中克隆对象的最佳方法是什么
例如,我想避免以下情况:
var obj1 = {x: 5, y:5};
var obj2 = obj1;
obj2.x = 6;
console.log(obj1.x); // logs 6
该对象很可能包含复杂的类型作为属性,因此无法解决简单的for(obj1中的var x)。我需要自己编写一个递归克隆吗,还是内置了一些我看不到的东西?
Answers:
简洁的深层副本:
var obj2 = JSON.parse(JSON.stringify(obj1));
注意:在Node.js的文档中,此解决方案现已标记为已弃用:
从未打算在内部Node.js模块外部使用util._extend()方法。社区仍然找到并使用了它。
它已被弃用,不应在新代码中使用。JavaScript通过Object.assign()具有非常相似的内置功能。
原始答案:
对于浅表副本,请使用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;
};
_*
应该意味着它是私有方法,不应该被依赖吗?
util._extend()
方法从未打算在内部Node.js模块之外使用。社区仍然找到并使用了它。 它已被弃用,不应在新代码中使用。JavaScript具有非常相似的内置功能,直到Object.assign().
我很惊讶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;
}
});
这将定义您可以使用的扩展方法。代码来自本文。
您可以从JQuery使用扩展功能:
var newClone= jQuery.extend({}, oldObject);
var deepClone = jQuery.extend(true, {}, oldObject);
也有一个Node.js插件:
https://github.com/shimondoodkin/nodejs-clone-extend
要在没有JQuery或插件的情况下执行此操作,请在此处阅读以下内容:
查看underscore.js。它具有克隆和扩展功能,以及许多其他非常有用的功能。
这可能很有用:将Underscore模块与Node.js一起使用
如果不想“自己动手”,这里有一些Node模块。这个看起来不错:https://www.npmjs.com/package/clone
看起来它可以处理各种内容,包括循环引用。从github页面:
clone master克隆对象,数组,Date对象和RegEx对象。一切都是递归克隆的,因此,例如,您可以在对象数组中克隆日期。[...]循环引用?是的
该代码也是有效的,因为Object.create()方法使用指定的原型对象和属性创建一个新对象。
var obj1 = {x:5, y:5};
var obj2 = Object.create(obj1);
obj2.x; //5
obj2.x = 6;
obj2.x; //6
obj1.x; //5
在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] ];
}
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"}
方法Object.keys需要JavaScript 1.8.5; nodeJS v0.4.11支持此方法
但是对于嵌套对象,当然需要实现递归函数
另一种解决方案是使用本机JSON(在JavaScript 1.7中实现),但是它比上一个慢得多(慢了10倍)
var a = {"a": i, "b": i*i};
var b = JSON.parse(JSON.stringify(a));
b.a = 0;
Github上还有一个项目,旨在成为更直接的港口jQuery.extend()
:
https://github.com/dreamerslab/node.extend
一个示例,从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);
在寻找真正的克隆选项时,我偶然发现了ridcully的链接:
http://my.opera.com/GreyWyvern/blog/show.dml/1725165
我修改了该页面上的解决方案,以使附加到Object
原型的功能无法枚举。这是我的结果:
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;
}
});
希望这对其他人也有帮助。请注意,有一些警告...尤其是对于名为“ clone”的属性。这对我来说很好。我不以为然。同样,我只更改了定义方式。
没有一个答案让我满意,有几个没有用,或者仅仅是浅表克隆,来自@ clint-harris并使用JSON.parse / stringify的答案很好,但是很慢。我发现了一个可以快速进行深度克隆的模块:https : //github.com/AlexeyKupershtokh/node-v8-clone
在node.js中没有内置的方法可以对对象进行真实的克隆(深拷贝)。有一些棘手的情况,因此您绝对应该为此使用一个库。我为我的simpleoo库编写了这样的函数。您可以使用deepCopy
不需要,函数,而无需使用库中的任何其他函数(该函数很小)。该函数支持克隆多种数据类型,包括数组,日期和正则表达式,它支持递归引用,并且还可以与构造函数具有必需参数的对象一起使用。
这是代码:
//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
您可以原型对象,然后在每次要使用和更改对象时调用对象实例:
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
您还可以将参数传递给对象构造函数
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
希望这会有所帮助。
npm install underscore
2.var _ = require('underscore')
3_.clone(objToClone)
.;