Javascript 这是在 ES6 中克隆对象的好方法吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39736397/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 22:51:24  来源:igfitidea点击:

Is this a good way to clone an object in ES6?

javascriptecmascript-6javascript-objects

提问by Dmitry Fadeev

Googling for "javascript clone object" brings some really weird results, some of them are hopelessly outdated and some are just too complex, isn't it as easy as just:

谷歌搜索“javascript clone object”会带来一些非常奇怪的结果,其中一些已经过时了,有些太复杂了,是不是很简单:

let clone = {...original};

Is there anything wrong with this?

这有什么问题吗?

回答by Mark Shust at M.academy

This is good for shallow cloning. The object spread is a standard part of ECMAScript 2018.

这有利于浅克隆。该物体传播是ECMAScript的2018的标准组成部分

For deep cloning you'll need a different solution.

对于深度克隆,您需要不同的解决方案

const clone = {...original}to shallow clone

const clone = {...original}浅克隆

const newobj = {...original, prop: newOne}to immutably add another prop to the original and store as a new object.

const newobj = {...original, prop: newOne}不变地将另一个道具添加到原始道具并存储为新对象。

回答by Alberto Rivera

EDIT: When this answer was posted, {...obj}syntax was not available in most browsers. Nowadays, you should be fine using it (unless you need to support IE 11).

编辑:发布此答案时,{...obj}语法在大多数浏览器中不可用。现在,您应该可以使用它(除非您需要支持 IE 11)。

Use Object.assign.

使用 Object.assign。

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

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

var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

However, this won't make a deep clone. There is no native way of deep cloning as of yet.

但是,这不会进行深度克隆。目前还没有深度克隆的本土方法。

EDIT: As @Mike 'Pomax' Kamermans mentioned in the comments, you can deep clone simple objects (ie. no prototypes, functions or circular references) using JSON.parse(JSON.stringify(input))

编辑:正如评论中提到的@Mike 'Pomax' Kamermans,您可以使用深度克隆简单对象(即没有原型、函数或循环引用) JSON.parse(JSON.stringify(input))

回答by marcel

if you don't want to use json.parse(json.stringify(object)) you could create recursively key-value copies:

如果你不想使用 json.parse(json.stringify(object)) 你可以递归地创建键值副本:

function copy(item){
  let result = null;
  if(!item) return result;
  if(Array.isArray(item)){
    result = [];
    item.forEach(element=>{
      result.push(copy(element));
    });
  }
  else if(item instanceof Object && !(item instanceof Function)){ 
    result = {};
    for(let key in item){
      if(key){
        result[key] = copy(item[key]);
      }
    }
  }
  return result || item;
}

But the best way is to create a class that can return a clone of it self

但最好的方法是创建一个可以返回它自己的克隆的类

class MyClass{
    data = null;
    constructor(values){ this.data = values }
    toString(){ console.log("MyClass: "+this.data.toString(;) }
    remove(id){ this.data = data.filter(d=>d.id!==id) }
    clone(){ return new MyClass(this.data) }
}

回答by shaheer shukur

If the methods you used isn't working well with objects involving data types like Date, try this

如果您使用的方法不能很好地处理涉及Date等数据类型的对象,请尝试此操作

Import _

进口 _

import * as _ from 'lodash';

Deep clone object

深度克隆对象

myObjCopy = _.cloneDeep(myObj);

回答by Shane Gannon

Following on from the answer by @marcel I found some functions were still missing on the cloned object. e.g.

继@marcel 的回答之后,我发现克隆对象上仍然缺少一些函数。例如

function MyObject() {
  var methodAValue = null,
      methodBValue = null

  Object.defineProperty(this, "methodA", {
    get: function() { return methodAValue; },
    set: function(value) {
      methodAValue = value || {};
    },
    enumerable: true
  });

  Object.defineProperty(this, "methodB", {
    get: function() { return methodAValue; },
    set: function(value) {
      methodAValue = value || {};
    }
  });
}

where on MyObject I could clone methodA but methodB was excluded. This occurred because it is missing

在 MyObject 上,我可以克隆 methodA 但排除了 methodB。发生这种情况是因为它丢失了

enumerable: true

which meant it did not show up in

这意味着它没有出现在

for(let key in item)

Instead I switched over to

相反,我切换到

Object.getOwnPropertyNames(item).forEach((key) => {
    ....
  });

which will include non-enumerable keys.

这将包括不可枚举的键。

I also found that the prototype (proto) was not cloned. For that I ended up using

我还发现原型(proto)没有被克隆。为此,我最终使用了

if (obj.__proto__) {
  copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}

PS: Frustrating that I could not find a built in function to do this.

PS:令人沮丧的是,我找不到内置函数来执行此操作。

回答by rafee_que_

You can do it like this as well,

你也可以这样做

let copiedData = JSON.parse(JSON.stringify(data));

回答by Saksham

All the methods above do not handle deep cloning of objects where it is nested to n levels. I did not check its performance over others but it is short and simple.

上面的所有方法都不能处理嵌套到 n 级的对象的深度克隆。我没有检查它的性能,但它简短而简单。

The first example below shows object cloning using Object.assignwhich clones just till first level.

下面的第一个示例显示了使用Object.assignwhich 克隆直到第一级的对象克隆。

var person = {
    name:'saksham',
    age:22,
    skills: {
        lang:'javascript',
        experience:5
    }
}

newPerson = Object.assign({},person);
newPerson.skills.lang = 'angular';
console.log(newPerson.skills.lang); //logs Angular

Using the below approach deep clones object

使用以下方法深度克隆对象

var person = {
    name:'saksham',
    age:22,
    skills: {
        lang:'javascript',
        experience:5
    }
}

anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = 'angular';
console.log(person.skills.lang); //logs javascript

回答by Mohamed Elshahawy

We can do that with two way:
1- First create a new object and replicate the structure of the existing one by iterating 
 over its properties and copying them on the primitive level.

let user = {
     name: "John",
     age: 30
    };

    let clone = {}; // the new empty object

    // let's copy all user properties into it
    for (let key in user) {
      clone[key] = user[key];
    }

    // now clone is a fully independant clone
    clone.name = "Pete"; // changed the data in it

    alert( user.name ); // still John in the original object

2- Second we can use the method Object.assign for that 
    let user = { name: "John" };
    let permissions1 = { canView: true };
    let permissions2 = { canEdit: true };

    // copies all properties from permissions1 and permissions2 into user
    Object.assign(user, permissions1, permissions2);

  -Another example

    let user = {
      name: "John",
      age: 30
    };

    let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.

But Object.assign() not create a deep clone

但是 Object.assign() 不会创建深度克隆

let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

let clone = Object.assign({}, user);

alert( user.sizes === clone.sizes ); // true, same object

// user and clone share sizes
user.sizes.width++;       // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one

To fix that, we should use the cloning loop that examines each value of user[key] and, if it's an object, then replicate its structure as well. That is called a “deep cloning”.

为了解决这个问题,我们应该使用克隆循环来检查 user[key] 的每个值,如果它是一个对象,那么也复制它的结构。这就是所谓的“深度克隆”。

There's a standard algorithm for deep cloning that handles the case above and more complex cases, called the Structured cloning algorithm. In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library lodashthe method is called _.cloneDeep(obj).

有一种深度克隆的标准算法可以处理上述情况和更复杂的情况,称为结构化克隆算法。为了不重新发明轮子,我们可以使用 JavaScript 库lodash 中的一个工作实现,该方法称为_.cloneDeep(obj)