在node.js中克隆对象的最佳方法是什么
e.g。我想避免以下情况:
var obj1 = {x: 5, y:5};
var obj2 = obj1;
obj2.x = 6;
console.log(obj1.x); // logs 6
对象可能包含复杂类型作为属性,因此简单的(obj1中的var x)无法解决。我是否需要自己编写一个递归克隆,或者是否有内置的东西我没有看到?
答案 0 :(得分:277)
低褶皱深拷贝:
var obj2 = JSON.parse(JSON.stringify(obj1));
注意:此解决方案现已在documentation of Node.js中标记为已弃用:
util._extend()方法从不打算在内部Node.js模块之外使用。无论如何,社区发现并使用了它。
不推荐使用,不应在新代码中使用。 JavaScript通过Object.assign()提供了非常相似的内置功能。</ p>
原始回答::
对于浅层副本,请使用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
节点_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;
};
答案 1 :(得分:217)
我很惊讶Object.assign
没有被提及。
let cloned = Object.assign({}, source);
如果可用(例如Babel),您可以使用object spread operator:
let cloned = { ... source };
答案 2 :(得分:23)
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;
}
});
这将定义您可以使用的扩展方法。代码来from this article.
答案 3 :(得分:17)
var obj2 = JSON.parse(JSON.stringify(obj1));
答案 4 :(得分:13)
您可以使用JQuery中的extend函数:
var newClone= jQuery.extend({}, oldObject);
var deepClone = jQuery.extend(true, {}, oldObject);
还有一个Node.js插件:
https://github.com/shimondoodkin/nodejs-clone-extend
如果没有JQuery或Plugin,请在此处阅读:
答案 5 :(得分:12)
结帐underscore.js。它同时具有clone和extend以及许多其他非常有用的功能。
答案 6 :(得分:8)
如果不想“自己动手”,那里有一些Node模块。这个看起来不错:https://www.npmjs.com/package/clone
看起来它处理所有类型的东西,包括循环引用。来自github页面:
clone master克隆对象,数组,Date对象和RegEx 对象。一切都是递归克隆的,这样你就可以克隆日期 例如,在对象的数组中。 [...]循环参考?是的!
答案 7 :(得分:6)
在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;
答案 8 :(得分:6)
此代码也起作用 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
答案 9 :(得分:5)
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);
答案 10 :(得分:4)
答案 11 :(得分:3)
寻找一个真正的克隆选项,我偶然发现了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”的属性。这对我很有用。我写这篇文章并不值得赞扬。同样,我只改变了它的定义方式。
答案 12 :(得分:2)
大家都很痛苦,但解决方法很简单。
var obj1 = {x: 5, y:5};
var obj2 = {...obj1};
//繁荣
答案 13 :(得分:1)
答案 14 :(得分:0)
您还可以使用此 clone 库来深克隆对象。
npm install --save clone
const clone = require('clone');
const clonedObject = clone(sourceObject);
答案 15 :(得分:0)
另一种解决方案是使用以下方法直接封装在新变量中:
obj1= {...obj2}
答案 16 :(得分:0)
npm install node-v8-clone
最快的克隆,它从node.js打开本机克隆方法
var clone = require('node-v8-clone').clone;
var newObj = clone(obj, true); //true - deep recursive clone
答案 17 :(得分:0)
没有内置方法可以在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;
};
答案 18 :(得分:0)
没有一个答案让我感到满意,有几个不起作用或者只是浅层克隆,来自@ clint-harris并使用JSON.parse / stringify的答案很好但很慢。我找到了一个快速深度克隆的模块:https://github.com/AlexeyKupershtokh/node-v8-clone
答案 19 :(得分:0)
如果你正在使用咖啡脚本,它就像:
一样简单newObject = {}
newObject[key] = value for own key,value of oldObject
虽然这不是一个深刻的克隆。
答案 20 :(得分:-2)
您可以对对象进行原型设计,然后在每次要使用和更改对象时调用对象实例:
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
希望这有用。