简体   繁体   English

在 Node.js 中克隆一个 Object

[英]Cloning an Object in Node.js

What is the best way to clone an object in node.js在 node.js 中克隆 object 的最佳方法是什么

eg I want to avoid the situation where:例如,我想避免以下情况:

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

The object may well contain complex types as attributes, so a simple for(var x in obj1) wouldn't solve. object 很可能包含复杂类型作为属性,因此简单的 for(var x in obj1) 无法解决。 Do I need to write a recursive clone myself or is there something built in that I'm not seeing?我是否需要自己编写一个递归克隆,或者是否有一些我没有看到的内置内容?

Possibility 1可能性 1

Low-frills deep copy:低调的深拷贝:

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

Possibility 2 (deprecated)可能性 2(已弃用)

Attention: This solution is now marked as deprecated in thedocumentation of Node.js :注意:此解决方案现在在Node.js 的文档中标记为已弃用:

The util._extend() method was never intended to be used outside of internal Node.js modules. util._extend() 方法从未打算在内部 Node.js 模块之外使用。 The community found and used it anyway.社区还是找到并使用了它。

It is deprecated and should not be used in new code.它已被弃用,不应在新代码中使用。 JavaScript comes with very similar built-in functionality through Object.assign(). JavaScript 通过 Object.assign() 提供了非常相似的内置功能。

Original answer: :原答案::

For a shallow copy, use Node's built-in util._extend() function.对于浅拷贝,使用 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

Source code of Node's _extend function is in here: https://github.com/joyent/node/blob/master/lib/util.js 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;
};

I'm surprised Object.assign hasn't been mentioned.我很惊讶Object.assign没有被提及。

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

If available (eg Babel), you can use the object spread operator :如果可用(例如 Babel),您可以使用对象扩展运算符

let cloned = { ... source };
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;
    }
});

This will define an extend method that you can use.这将定义一个可以使用的扩展方法。 Code comes from this article.代码来自这篇文章。

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

You can use the extend function from JQuery:您可以使用 JQuery 的扩展功能:

var newClone= jQuery.extend({}, oldObject);  
var deepClone = jQuery.extend(true, {}, oldObject); 

There is a Node.js Plugin too:还有一个 Node.js 插件:

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

To do it without JQuery or Plugin read this here:要在没有 JQuery 或插件的情况下执行此操作,请在此处阅读:

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

Check out underscore.js .查看underscore.js It has both clone and extend and many other very useful functions.它同时具有克隆扩展以及许多其他非常有用的功能。

This can be useful: Using the Underscore module with Node.js这可能很有用: 在 Node.js 中使用 Underscore 模块

There are some Node modules out there if don't want to "roll your own".如果不想“自己动手”,可以使用一些 Node 模块。 This one looks good: https://www.npmjs.com/package/clone这个看起来不错: https ://www.npmjs.com/package/clone

Looks like it handles all kinds of stuff, including circular references.看起来它处理各种东西,包括循环引用。 From the github page:github页面:

clone masters cloning objects, arrays, Date objects, and RegEx objects.克隆大师克隆对象、数组、日期对象和正则表达式对象。 Everything is cloned recursively, so that you can clone dates in arrays in objects, for example.一切都是递归克隆的,例如,您可以在对象的数组中克隆日期。 [...] Circular references? [...] 循环引用? Yep!是的!

There is another library lodash , it has clone and cloneDeep .还有另一个库lodash ,它有clonecloneDeep

clone will clone your object but not create a new instance for non-primitive values, instead it will use the referrence to the original object clone将克隆您的对象,但不会为非原始值创建新实例,而是使用对原始对象的引用

cloneDeep will create literally new objects without having any referrence to the original object, so it more safe when you have to change the object afterwards. cloneDeep将在不引用原始对象的情况下创建真正的新对象,因此当您必须在之后更改对象时它更安全。

This code is also work cause The Object.create() method creates a new object with the specified prototype object and properties.此代码也是工作原因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

Simple and the fastest way to clone an Object in NodeJS is to use Object.keys( obj ) method在 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"}

The method Object.keys requires JavaScript 1.8.5; Object.keys 方法需要 JavaScript 1.8.5; nodeJS v0.4.11 supports this method nodeJS v0.4.11 支持此方法

but of course for nested objects need to implement recursive func但当然对于嵌套对象需要实现递归函数


Other solution is to use native JSON (Implemented in JavaScript 1.7), but it's much slower (~10 times slower) than previous one其他解决方案是使用原生 JSON(在 JavaScript 1.7 中实现),但它比以前的要慢得多(约慢 10 倍)

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

Y'all suffering yet the solution is simple.你们都在受苦,但解决方案很简单。

var obj1 = {x: 5, y:5};

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

There is also a project on Github that aims to be a more direct port of the jQuery.extend() : Github 上还有一个项目旨在成为jQuery.extend()的更直接端口:

https://github.com/dreamerslab/node.extend https://github.com/dreamerslab/node.extend

An example, modified from the jQuery docs :一个示例,从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);

Looking for a true clone option, I stumbled across ridcully's link to here:在寻找真正的克隆选项时,我偶然发现了 ridcully 的链接:

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

I modified the solution on that page so that the function attached to the Object prototype is not enumerable.我修改了该页面上的解决方案,使附加到Object原型的函数不可枚举。 Here is my result:这是我的结果:

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

Hopefully this helps someone else as well.希望这对其他人也有帮助。 Note that there are some caveats... particularly with properties named "clone".请注意,有一些警告......特别是名为“克隆”的属性。 This works well for me.这对我很有效。 I don't take any credit for writing it.我不认为写它有任何功劳。 Again, I only changed how it was being defined.同样,我只改变了它的定义方式。

You can also use SugarJS in NodeJS.你也可以在 NodeJS 中使用 SugarJS。

http://sugarjs.com/ http://sugarjs.com/

They have a very clean clone feature: http://sugarjs.com/api/Object/clone他们有一个非常干净的克隆功能: http ://sugarjs.com/api/Object/clone

None of the answers satisfied me, several don't work or are just shallow clones, answers from @clint-harris and using JSON.parse/stringify are good but quite slow.没有一个答案让我满意,有几个不起作用或只是浅层克隆,@clint-harris 和使用 JSON.parse/stringify 的答案很好,但速度很慢。 I found a module that does deep cloning fast: https://github.com/AlexeyKupershtokh/node-v8-clone我发现了一个可以快速进行深度克隆的模块: https ://github.com/AlexeyKupershtokh/node-v8-clone

There is no built-in way to do a real clone (deep copy) of an object in node.js.在 node.js 中没有内置方法可以对对象进行真正的克隆(深拷贝)。 There are some tricky edge cases so you should definitely use a library for this.有一些棘手的边缘情况,因此您绝对应该为此使用库。 I wrote such a function for my simpleoo library.我为我的simpleoo库编写了这样一个函数。 You can use the deepCopy function without using anything else from the library (which is quite small) if you don't need it.如果不需要,您可以使用deepCopy函数,而无需使用库中的任何其他内容(非常小)。 This function supports cloning multiple data types, including arrays, dates, and regular expressions, it supports recursive references, and it also works with objects whose constructor functions have required parameters.此函数支持克隆多种数据类型,包括数组、日期和正则表达式,它支持递归引用,并且它还适用于构造函数具有所需参数的对象。

Here is the code:这是代码:

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

You can also use this clone library to deep clone objects.您还可以使用此克隆库来深度克隆对象。

 npm install --save clone
const clone = require('clone');

const clonedObject = clone(sourceObject);

If you're working with ordinary objects and arrays, and don't care about cloning functions or recursive references, here's a simple deepClone implementation which works on ordinary objects, arrays, strings, numbers, regex, dates, etc.如果您使用的是普通对象和数组,并且不关心克隆函数或递归引用,这里有一个简单的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);

Good article about this problem: https://www.samanthaming.com/tidbits/70-3-ways-to-clone-objects/关于这个问题的好文章: https ://www.samanthaming.com/tidbits/70-3-ways-to-clone-objects/

var obj1 = {x: 5, y:5};
var obj2 = Object.assign({}, obj1 );
    
obj2  = {z: 10};
    
console.log(obj1);
console.log(obj2);

If you're using coffee-script, it's as easy as:如果您使用的是咖啡脚本,则很简单:

newObject = {}
newObject[key] = value  for own key,value of oldObject

Though this isn't a deep clone.虽然这不是一个深度克隆。

npm install node-v8-clone

Fastest cloner, it open native clone method from node.js最快的克隆器,它从 node.js 打开本地克隆方法

var clone = require('node-v8-clone').clone;
var newObj = clone(obj, true); //true - deep recursive clone

另一种解决方案是直接封装在新变量中,使用: obj1= {...obj2}

You can prototype object and then call object instance every time you want to use and change object:您可以在每次要使用和更改对象时创建对象原型,然后调用对象实例:

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

You can also pass arguments to object constructor您还可以将参数传递给对象构造函数

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

Hope this is helpful.希望这会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM