克隆Node.js中的对象

时间:2011-02-20 07:08:05

标签: javascript node.js

在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)无法解决。我是否需要自己编写一个递归克隆,或者是否有内置的东西我没有看到?

21 个答案:

答案 0 :(得分:277)

可能性1

低褶皱深拷贝:

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

可能性2(已弃用)

注意:此解决方案现已在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,请在此处阅读:

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

答案 5 :(得分:12)

结帐underscore.js。它同时具有cloneextend以及许多其他非常有用的功能。

这很有用:Using the Underscore module with Node.js

答案 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)

还有另一个库lodash,它有clonecloneDeep,还有许多其他有用的功能。

答案 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)

您也可以在NodeJS中使用SugarJS。

http://sugarjs.com/

他们有一个非常干净的克隆功能: http://sugarjs.com/api/Object/clone

答案 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

希望这有用。