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

Javascript 这是在ES6中克隆对象的好方法吗?,javascript,ecmascript-6,javascript-objects,Javascript,Ecmascript 6,Javascript Objects,谷歌搜索“javascript克隆对象”会带来一些非常奇怪的结果,其中一些已经过时,有些太复杂了,不是很简单吗 let clone = {...original}; 这有什么问题吗?编辑:发布此答案时,{…obj}语法在大多数浏览器中都不可用。现在,你应该可以很好地使用它(除非你需要支持IE11) 使用Object.assign 但是,这不会产生深度克隆。到目前为止,还没有一种本土的深度克隆方法 编辑:正如@Mike'Pomax'Kamermans在评论中提到的,您可以使用JSON.pars

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

let clone = {...original};

这有什么问题吗?

编辑:发布此答案时,
{…obj}
语法在大多数浏览器中都不可用。现在,你应该可以很好地使用它(除非你需要支持IE11)

使用Object.assign

但是,这不会产生深度克隆。到目前为止,还没有一种本土的深度克隆方法


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

要进行深度克隆,你需要一个

const clone={…original}
到浅层克隆


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

如果不想使用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;
}
但最好的方法是创建一个类,该类可以返回它自己的克隆

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) }
}
但是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
为了解决这个问题,我们应该使用克隆循环来检查user[key]的每个值,如果它是一个对象,那么还应该复制它的结构。这就是所谓的“深度克隆”

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

如果您使用的方法不能很好地处理涉及数据类型(如Date)的对象,请尝试以下方法

导入<代码>\

import * as _ from 'lodash';
深度克隆对象

myObjCopy = _.cloneDeep(myObj);

根据@marcel的回答,我发现克隆对象上仍然缺少一些函数。e、 g

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 || {};
    }
  });
}
在MyObject上,我可以克隆methodA,但methodB被排除在外。发生这种情况是因为它丢失了

enumerable: true
这意味着它没有出现在

for(let key in item)
相反,我换了工作

Object.getOwnPropertyNames(item).forEach((key) => {
    ....
  });
其中包括不可枚举的键

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

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

PS:令人沮丧的是,我找不到一个内置函数来实现这一点。

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

下面的第一个示例显示了使用
object进行对象克隆。指定仅克隆到第一级的

var-person={
姓名:'saksham',
年龄:22,,
技能:{
朗:“javascript”,
经验:5
}
}
newPerson=Object.assign({},person);
newPerson.skills.lang='angular';

console.log(newPerson.skills.lang)//你也可以这样做

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

我找到了一个解决方案,它似乎也复制了函数,如果这个例子是错误的,请纠正我

注意,我还没有在更复杂的对象情况下测试这个方法,例如,这些情况将包括具有此功能的方法,以供参考

以早餐价格为例,我在全球范围内都有此价格,但我想针对酒店房间单独调整此价格

// make an object for a booking option
var opt_resa = { breakfast_val: 900 }

// i define a function for opt_resa : 
opt_resa.func = function(){ alert('i am a function'); }

// copy object in modif.opt_resa :
var modif = { opt_resa : {} }

for ( var v in opt_resa ){

    modif.opt_resa[v] = $.o.opt_resa[v];
}

// test
modif.opt_resa.breakfast_val = 1500;

// old value
console.log( opt_resa.breakfast_val );
// output : 900

// modified value
console.log( modif.opt_resa.breakfast_val );
// output : 1500

// function copied
modif.opt_resa.func(); 
// this function works

这是不合法的。但如果不是,这不是克隆:您的克隆和原始属性现在都指向相同的东西。例如,
original={a:[1,2,3]}
提供了一个克隆,其中
clone.a
字面上是
original.a
。通过
clone
original
进行修改会修改相同的内容,所以不,这是坏的=)@AlbertoRivera这是一种有效的JavaScript,因为它很可能是JavaScript标准的未来补充。@Frxstrem,问题是关于ES6,这不是有效的JavaScript=)浅克隆还是深克隆?你是对的,它不是有效的ES6,它是有效的ES9。如果您的对象是一个真正的对象文字,并且是纯数据,那么就有一个,在这种情况下,
JSON.parse(JSON.stringify(input))
是一个合适的深度克隆。然而,当原型、函数或循环引用发挥作用时,该解决方案就不再有效了。@Mike'Pomax'Kamermans这是真的。但是,丢失getter和setter的功能是很可怕的……如果您需要一个通用函数来深度克隆任何对象,请查看。现在有一种方法可以做到。@DanDascalescu尽管它是实验性的,但看起来很有希望。谢谢你的信息!然而,这不是一个肤浅的克隆吗?与中一样,属性不是递归克隆的,是吗?因此,original.innerObject==clone.innerObject并更改original.innerObject.property将更改clone.innerObject.property.yes,这是一个浅克隆。如果您想要深度克隆,必须使用
JSON.parse(JSON.stringify(input))
/!\parse(JSON.stringify(input))会弄乱日期,未定义。。。这不是克隆的灵丹妙药!请参阅:hack JSON.stringify()/JSON.parse()真的是ES6中深度克隆对象的推荐方法吗?我一直看到它被推荐。令人不安。@MarkShust
JSON.parse(JSON.stringify(input))
将不起作用,因为如果有
函数
无穷大
作为值,它只会在它们的位置赋值
null
。只有当值是简单的
文本
而不是
函数
时,它才会起作用。JSON.parse/stringify被认为是一种糟糕的深度克隆方法。请检查之前的答案以及相关问题。另外,这对ES6来说也不是什么新鲜事。@DanDascalescu我知道这一点,我认为将其用于简单对象不应该是一个问题。其他人在同一篇文章的回答中甚至在评论中也提到了这一点。我认为这不值得一试
let copiedData = JSON.parse(JSON.stringify(data));
// make an object for a booking option
var opt_resa = { breakfast_val: 900 }

// i define a function for opt_resa : 
opt_resa.func = function(){ alert('i am a function'); }

// copy object in modif.opt_resa :
var modif = { opt_resa : {} }

for ( var v in opt_resa ){

    modif.opt_resa[v] = $.o.opt_resa[v];
}

// test
modif.opt_resa.breakfast_val = 1500;

// old value
console.log( opt_resa.breakfast_val );
// output : 900

// modified value
console.log( modif.opt_resa.breakfast_val );
// output : 1500

// function copied
modif.opt_resa.func(); 
// this function works