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

例:我想避免以下情况:

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

对象很可能包含复杂类型作为属性,所以简单的for(var x in obj1)解决不了问题。我需要自己写一个递归克隆吗?还是有一些我没有看到的内置的东西?


当前回答

在NodeJS中克隆Object的最简单和最快的方法是使用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支持此方法

当然对于嵌套对象需要实现递归func


另一个解决方案是使用原生JSON(在JavaScript 1.7中实现),但它比之前的要慢得多(大约慢10倍)

var a = {"a": i, "b": i*i};
var b = JSON.parse(JSON.stringify(a));
b.a = 0;

其他回答

在NodeJS中克隆Object的最简单和最快的方法是使用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支持此方法

当然对于嵌套对象需要实现递归func


另一个解决方案是使用原生JSON(在JavaScript 1.7中实现),但它比之前的要慢得多(大约慢10倍)

var a = {"a": i, "b": i*i};
var b = JSON.parse(JSON.stringify(a));
b.a = 0;

可能性1

低装饰深度复制:

var obj2 = JSON.parse(JSON.stringify(obj1));

可能性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

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;
};

还有另一个库lodash,它有clone和cloneDeep。

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

cloneDeep将在不引用原始对象的情况下创建新的对象,因此当您随后必须更改对象时更安全。

如果你正在使用普通对象和数组,并且不关心克隆函数或递归引用,这里有一个简单的deepClone实现,它适用于普通对象、数组、字符串、数字、正则表达式、日期等。

// Simple Deep Clone
// Does not clone functions or handle recursive references.
function deepClone(original) {
  if (original instanceof RegExp) {
    return new RegExp(original);
  } else if (original instanceof Date) {
    return new Date(original.getTime());
  } else if (Array.isArray(original)) {
    return original.map(deepClone);
  } else if (typeof original === 'object' && original !== null) {
    const clone = {};
    Object.keys(original).forEach(k => {
      clone[k] = deepClone(original[k]);
    });
    return clone;
  }
  return original;
}

// Usage:

const obj = { n: 1, a: [ { a: 1 }, { a: 2 } ], d: new Date(), s: 'foo' };
const clone = deepClone(obj);
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;
    }
});

这将定义一个您可以使用的扩展方法。代码来自本文。