这是在 ES6 中克隆对象的好方法吗?
Is this a good way to clone an object in ES6?
谷歌搜索 "javascript clone object" 会带来一些非常奇怪的结果,其中一些已经过时了,而另一些则太复杂了,是不是就这么简单:
let clone = {...original};
这有什么问题吗?
编辑:发布此答案时,{...obj}
语法在大多数浏览器中不可用。现在,你应该可以很好地使用它(除非你需要支持 IE 11)。
使用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 }
但是,这不会产生深度克隆。目前还没有原生的深度克隆方法。
编辑:正如@Mike 'Pomax' Kamermans 在评论中提到的那样,您可以使用 JSON.parse(JSON.stringify(input))
深度克隆简单对象(即没有原型、函数或循环引用)
这对于浅层克隆很好。 object spread is a standard part of ECMAScript 2018.
对于深度克隆,您需要 different solution.
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 可以 return 自我克隆
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.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] 的每个值,如果它是一个对象,那么也复制它的结构。这就是所谓的“深度克隆”。
有一种深度克隆的标准算法可以处理上述情况和更复杂的情况,称为结构化 cloning algorithm。
为了不重新发明轮子,我们可以使用 JavaScript 库 lodash the method is called _.cloneDeep(obj).
中的有效实现
如果您使用的方法不适用于涉及 Date 等数据类型的对象,试试这个
导入_
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) => {
....
});
这将包括不可枚举的键。
我还发现原型(proto)没有被克隆。为此,我最终使用了
if (obj.__proto__) {
copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}
PS:令人沮丧的是我找不到内置函数来执行此操作。
以上所有方法均不处理嵌套到 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));
我找到了一个似乎也可以复制函数的解决方案,如果此示例有误,请纠正我。
注意,我还没有用更复杂的对象案例测试过这个方法,例如,将包括带有 this 的方法以供参考
以早餐的价格为例,我在全球都有这个价格,但我想针对酒店房间单独调整它
// 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); }
谷歌搜索 "javascript clone object" 会带来一些非常奇怪的结果,其中一些已经过时了,而另一些则太复杂了,是不是就这么简单:
let clone = {...original};
这有什么问题吗?
编辑:发布此答案时,{...obj}
语法在大多数浏览器中不可用。现在,你应该可以很好地使用它(除非你需要支持 IE 11)。
使用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 }
但是,这不会产生深度克隆。目前还没有原生的深度克隆方法。
编辑:正如@Mike 'Pomax' Kamermans 在评论中提到的那样,您可以使用 JSON.parse(JSON.stringify(input))
这对于浅层克隆很好。 object spread is a standard part of ECMAScript 2018.
对于深度克隆,您需要 different solution.
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 可以 return 自我克隆
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.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] 的每个值,如果它是一个对象,那么也复制它的结构。这就是所谓的“深度克隆”。
有一种深度克隆的标准算法可以处理上述情况和更复杂的情况,称为结构化 cloning algorithm。 为了不重新发明轮子,我们可以使用 JavaScript 库 lodash the method is called _.cloneDeep(obj).
中的有效实现如果您使用的方法不适用于涉及 Date 等数据类型的对象,试试这个
导入_
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) => {
....
});
这将包括不可枚举的键。
我还发现原型(proto)没有被克隆。为此,我最终使用了
if (obj.__proto__) {
copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}
PS:令人沮丧的是我找不到内置函数来执行此操作。
以上所有方法均不处理嵌套到 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));
我找到了一个似乎也可以复制函数的解决方案,如果此示例有误,请纠正我。
注意,我还没有用更复杂的对象案例测试过这个方法,例如,将包括带有 this 的方法以供参考
以早餐的价格为例,我在全球都有这个价格,但我想针对酒店房间单独调整它
// 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); }