Javascript 这是在ES6中克隆对象的好方法吗?
谷歌搜索“javascript克隆对象”会带来一些非常奇怪的结果,其中一些已经过时,有些太复杂了,不是很简单吗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
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中深度克隆对象的推荐方法吗?我一直看到它被推荐。令人不安。@MarkShustJSON.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