克隆Node.js中的对象

sli*_*fty 187 javascript node.js

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

例如,我想避免以下情况:

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

该对象可能包含复杂类型作为属性,因此简单的(obj1中的var x)无法解决.我是否需要自己编写一个递归克隆,或者是否有内置的东西我没有看到?

jim*_*mbo 289

可能性1

低褶边深拷贝:

var obj2 = JSON.parse(JSON.stringify(obj1));
Run Code Online (Sandbox Code Playgroud)

可能性2(已弃用)

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

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

它已弃用,不应在新代码中使用.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
Run Code Online (Sandbox Code Playgroud)

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;
};
Run Code Online (Sandbox Code Playgroud)

  • 是不是像`_*`这样的名字应该意味着它是一种私人方法,不应该依赖它? (27认同)
  • 这是错误的答案.根据节点的文档:https://nodejs.org/api/util.html#util_util_extend_obj _The util._extend()`方法从未打算在内部Node.js模块之外使用.社区无论如何都找到并使用它._ _**它已被弃用,不应在新代码中使用.**JavaScript通过`Object.assign()提供了非常相似的内置功能. (12认同)
  • 任何大小的每个JavaScript项目都有一个或多个extend()实现,Node也不例外.Node.js核心广泛使用了这个功能.引用艾萨克斯,["它不会很快到任何地方."](https://github.com/joyent/node/pull/4834#issuecomment-13981250) (7认同)
  • 这个问题特别要求递归克隆.这是一个浅层克隆. (5认同)
  • 对我来说很完美.比使用Object prototype imo更好 (2认同)

dja*_*ski 242

我很惊讶Object.assign没有提到.

let cloned = Object.assign({}, source);
Run Code Online (Sandbox Code Playgroud)

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

let cloned = { ... source };
Run Code Online (Sandbox Code Playgroud)

  • 这是一个浅薄的副本 (68认同)
  • 深度克隆警告,对于深度克隆仍需要使用其他替代方法.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Deep_Clone (12认同)
  • 这是一个比导入第三方库或使用不完美的JSON解决方法更好的解决方案.谢谢! (2认同)

Mic*_*lon 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;
    }
});
Run Code Online (Sandbox Code Playgroud)

这将定义您可以使用的extend方法.代码来自本文.

  • 是不是修改了Object.prototype应该是verboten?该文章链接也被打破了. (8认同)
  • 这真的有效吗?"if(name in dest)" - 只会在dest中已经存在的情况下更改属性.它应该被否定. (3认同)

小智 19

var obj2 = JSON.parse(JSON.stringify(obj1));
Run Code Online (Sandbox Code Playgroud)

  • 这已经在[现有答案](http://stackoverflow.com/a/7131327/447356)中提出,没有必要重复. (2认同)
  • 这个答案是错误的。JSON.stringify 获取一个日期对象并将其简化为字符串,然后在解析后将其保留为字符串,因此它会改变对象的状态,使您得到与最初的日期情况不同的对象。 (2认同)

小智 13

您可以使用JQuery中的extend函数:

var newClone= jQuery.extend({}, oldObject);  
var deepClone = jQuery.extend(true, {}, oldObject); 
Run Code Online (Sandbox Code Playgroud)

还有一个Node.js插件:

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

要在没有JQuery或插件的情况下执行此操作,请在此处阅读:

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


esp*_*esp 12

查看underscore.js.它有克隆扩展以及许多其他非常有用的功能.

这可能很有用:将Underscore模块与Node.js一起使用


Cli*_*ris 8

如果不想"自己动手",那里有一些Node模块.这个看起来不错:https://www.npmjs.com/package/clone

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

clone masters克隆对象,数组,Date对象和RegEx对象.例如,所有东西都是递归克隆的,因此您可以在对象的数组中克隆日期.[...]循环参考?是的!


Hir*_*ron 7

此代码也是工作原因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
Run Code Online (Sandbox Code Playgroud)

  • 这是一个浅薄的副本 (4认同)

小智 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"}
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)


Ran*_*ndy 5

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);
Run Code Online (Sandbox Code Playgroud)


zan*_*ngw 5

还有另一个库lodash,它有clonecloneDeep

clone 将克隆您的对象,但不会为非原始值创建新实例,而是使用对原始对象的引用

cloneDeep 将创建字面上的新对象,而无需对原始对象进行任何引用,因此当您之后必须更改对象时会更安全。


Nge*_*Lio 5

你们都在受苦,但解决方案很简单。

var obj1 = {x: 5, y:5};
Run Code Online (Sandbox Code Playgroud)

var obj2 = {...obj1}; // 繁荣