Nodejs:如何克隆对象

时间:2011-05-22 15:53:47

标签: javascript node.js

如果我克隆一个数组,我会使用cloneArr = arr.slice()

我想知道如何克隆nodejs中的对象。

12 个答案:

答案 0 :(得分:160)

对于不需要挤压每一滴性能的实用程序和类,我经常作弊并只使用JSON来执行深层复制:

function clone(a) {
   return JSON.parse(JSON.stringify(a));
}

这不是唯一的答案或最优雅的答案;所有其他答案都应该考虑到生产瓶颈。但是,这是一个快速而肮脏的解决方案,非常有效,并且在我克隆一个简单的属性哈希的大多数情况下都很有用。

答案 1 :(得分:28)

上述任何答案均未提及Object.assign。

let cloned = Object.assign({}, source);

如果您使用的是ES6,则可以使用点差运算符:

let cloned = { ... source };

参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

答案 2 :(得分:19)

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

看起来它处理所有类型的东西,包括循环引用。来自github页面:

  

clone master克隆对象,数组,Date对象和RegEx   对象。一切都是递归克隆的,这样你就可以克隆日期   例如,在对象的数组中。 [...]循环参考?是的!

答案 3 :(得分:10)

很难做一个通用但有用的克隆操作,因为应该递归克隆的内容以及应该复制的内容取决于特定对象应该如何工作。

可能有用的东西是

function clone(x)
{
    if (x === null || x === undefined)
        return x;
    if (typeof x.clone === "function")
        return x.clone();
    if (x.constructor == Array)
    {
        var r = [];
        for (var i=0,n=x.length; i<n; i++)
            r.push(clone(x[i]));
        return r;
    }
    return x;
}

在此代码中,逻辑是

  • 如果nullundefined只返回相同的内容(需要特殊情况,因为尝试查看是否存在clone方法是错误的)
  • 对象是否有clone方法?然后用那个
  • 是一个数组的对象?然后进行递归克隆操作
  • 否则只返回相同的值

此克隆功能应该允许轻松实现自定义克隆方法...例如

function Point(x, y)
{
    this.x = x;
    this.y = y;

    ...
}

Point.prototype.clone = function()
{
    return new Point(this.x, this.y);
};



function Polygon(points, style)
{
    this.points = points;
    this.style = style;

    ...
}

Polygon.prototype.clone = function()
{
    return new Polygon(clone(this.points),
                       this.style);
};

当您在对象中知道特定数组的正确克隆操作只是一个浅层副本时,您可以调用values.slice()而不是clone(values)

例如,在上面的代码中,我明确要求克隆多边形对象将克隆点,但将共享相同的样式对象。如果我想要克隆样式对象,那么我可以传递clone(this.style)

答案 4 :(得分:9)

没有用于克隆对象的本机方法。下划线实现_.clone这是一个浅层克隆。

_.clone = function(obj) {
  return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};

切片或延伸它。

这是_.extend

// extend the obj (first parameter)
_.extend = function(obj) {
  // for each other parameter
  each(slice.call(arguments, 1), function(source) {
    // loop through all properties of the other objects
    for (var prop in source) {
      // if the property is not undefined then add it to the object.
      if (source[prop] !== void 0) obj[prop] = source[prop];
    }
  });
  // return the object (first parameter)
  return obj;
};

Extend只是遍历所有项目并创建一个包含其中项目的新对象。

如果你想要

,你可以推出自己的天真实现
function clone(o) {
  var ret = {};
  Object.keys(o).forEach(function (val) {
    ret[val] = o[val];
  });
  return ret;
}

有充分的理由避免深度克隆,因为无法克隆封闭。

我个人问了一个关于deep cloning objects before的问题,我得出的结论是你不这样做。

我的建议是使用underscore并使用_.clone方法进行浅层克隆

答案 5 :(得分:9)

对于浅拷贝,我喜欢使用reduce模式(通常在模块中等),如下所示:

var newObject = Object.keys(original).reduce(function (obj, item) {
    obj[item] = original[item];
    return obj;
},{});

以下是几个选项的jsperf:http://jsperf.com/shallow-copying

答案 6 :(得分:7)

老问题,但到目前为止,有一个更优雅的答案;使用内置的utils._extend:

var extend = require("util")._extend;

var varToCopy = { test: 12345, nested: { val: 6789 } };

var copiedObject = extend({}, varToCopy);

console.log(copiedObject);

// outputs:
// { test: 12345, nested: { val: 6789 } }

请注意第一个参数与空对象{}的使用 - 这告诉扩展复制的对象需要复制到新对象。如果使用现有对象作为第一个参数,则第二个(以及所有后续)参数将在第一个参数变量上进行深度合并复制。

使用上面的示例变量,您也可以这样做:

var anotherMergeVar = { foo: "bar" };

extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar);

console.log(copiedObject);

// outputs:
// { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' }

非常方便的实用程序,特别是在我习惯在AngularJS和jQuery中扩展时。

希望这有助于其他人;对象引用覆盖是一种痛苦,每次都能解决它!

答案 7 :(得分:5)

您也可以使用 lodash 。它有clonecloneDeep方法。

var _= require('lodash');

var objects = [{ 'a': 1 }, { 'b': 2 }];

var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]);
// => true

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);

答案 8 :(得分:1)

根据您对克隆对象的处理方式,您可以利用javascript的原型继承机制,通过以下方式实现一个有点克隆的对象:

var clonedObject = Object.create(originalObject);

请记住,这不是一个完整的克隆 - 无论好坏。

一件好事是你实际上没有复制对象,所以内存占用率很低。

关于这种方法需要记住的一些棘手的事情是,原型链中定义的属性迭代有时会有所不同,并且原始对象的任何更改都会影响克隆对象,除非该属性已设置本身也是。

答案 9 :(得分:1)

我实施了完整的深层复制。我认为它是通用克隆方法的最佳选择,但它不处理循环引用。

用法示例:

parent = {'prop_chain':3}
obj = Object.create(parent)
obj.a=0; obj.b=1; obj.c=2;

obj2 = copy(obj)

console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
console.log(obj2, obj2.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3

parent.prop_chain=4
obj2.a = 15

console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 4
console.log(obj2, obj2.prop_chain)
// '{'a':15, 'b':1, 'c':2} 4

代码本身:

此代码使用原型复制对象,它还复制函数(可能对某人有用)。

function copy(obj) {
  // (F.prototype will hold the object prototype chain)
  function F() {}
  var newObj;

  if(typeof obj.clone === 'function')
    return obj.clone()

  // To copy something that is not an object, just return it:
  if(typeof obj !== 'object' && typeof obj !== 'function' || obj == null)
    return obj;

  if(typeof obj === 'object') {    
    // Copy the prototype:
    newObj = {}
    var proto = Object.getPrototypeOf(obj)
    Object.setPrototypeOf(newObj, proto)
  } else {
    // If the object is a function the function evaluate it:
    var aux
    newObj = eval('aux='+obj.toString())
    // And copy the prototype:
    newObj.prototype = obj.prototype
  }

  // Copy the object normal properties with a deep copy:
  for(var i in obj) {
    if(obj.hasOwnProperty(i)) {
      if(typeof obj[i] !== 'object')
        newObj[i] = obj[i]
      else
        newObj[i] = copy(obj[i])
    }
  }

  return newObj;
}

使用此副本,我无法找到原始副本和复制副本之间的任何差异,除非原始使用的结构封闭,所以我认为它是一个很好的实现。

我希望它有所帮助

答案 10 :(得分:1)

对于数组,可以使用

var arr = [1,2,3]; 
var arr_2 = arr ; 

print ( arr_2 ); 

<强> ARR = arr.slice(0);

print ( arr ); 

arr[1]=9999; 

print ( arr_2 ); 

答案 11 :(得分:1)

JavaScript中的对象和数组按引用使用调用,如果更新复制的值,则它可能会反映在原始对象上。 为防止这种情况,您可以使用lodash库cloneDeep方法深克隆对象,以防止引用传递 运行命令

  

npm install lodash

const ld = require('lodash')
const objectToCopy = {name: "john", age: 24}
const clonedObject = ld.cloneDeep(objectToCopy)