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

用 Google 搜索“ javascript 克隆对象”会得到一些非常奇怪的结果,有些已经过时了,有些太复杂了,是不是就像这样简单:

let clone = {...original};

这有什么问题吗?

168635 次浏览

编辑: 当这个答案被张贴,{...obj}语法不可用在大多数浏览器。现在,您应该可以很好地使用它(除非您需要支持 IE11)。

使用 Object.sign。

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 }

然而,这不会产生深度克隆,目前还没有原生的深度克隆方法。

编辑: 正如@Mike‘ Pomax’Kamermans 在评论中提到的,你可以深度克隆简单的对象(即。没有原型、函数或循环引用)

这是很好的 用于肤浅的克隆对象传播是 ECMAScript 2018的标准部分

为了进行深度克隆,你需要一个 不同的解决方案

const clone = {...original}呼叫浅层克隆

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

如果你不想使用 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) }
}
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.

但 Object.sign ()并没有创建一个深度克隆

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 库 浪荡的工作实现,该方法称为 _. cloneDeep (obj)

如果您使用的方法不能很好地处理涉及数据类型(如 日期)的对象,请尝试这样做

进口 _

import * as _ from 'lodash';

深度克隆物体

myObjCopy = _.cloneDeep(myObj);

在@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 || {};
}
});
}

在 MyObject 上,我可以克隆 methodA,但是 methodB 被排除在外。这是因为它丢失了吗

enumerable: true

这意味着它没有出现在

for(let key in item)

然而我却转向了

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

其中将包括不可枚举的键。

我还发现原型(原型)没有被克隆

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

备注: 我很沮丧,因为我找不到一个内置的函数来做这件事。

上述所有方法都不能处理嵌套到 n 级的对象的深度克隆。我没有检查它的性能超过其他人,但它是短期和简单的。

下面的第一个例子展示了使用 Object.assign进行对象克隆,这种克隆直到第一级。

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

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

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

你也可以这样做,

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] = 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

结构化克隆 你可以用这个方法

function Copy_Object(obj) { return structuredClone(obj); }