JavaScript中设置对象属性时所有元素值同步变化问题求助
嘿,这个问题我刚学JavaScript的时候也踩过一模一样的坑!咱们来拆解一下你遇到的问题:
问题根源:JavaScript的对象是引用类型
在JS里,像对象、数组这种复杂类型,赋值的时候并不是复制整个对象,而是复制了这个对象在内存中的引用地址。
看你的代码:
var materialStd = { flow: 123, name: 'Raoul' }; var obj = { id: 0, line: [ { id: 1, material: materialStd }, { id: 2, material: materialStd }, { id: 3, material: materialStd } ] }
这里你把materialStd赋值给了line数组里三个元素的material属性,但其实这三个material都指向同一个内存地址里的对象——也就是最初的materialStd。所以不管你修改哪一个line[x].material.flow,本质上都是在修改那个唯一的materialStd对象的flow属性,自然所有元素的对应属性都会跟着变。
怎么解决?创建独立的对象副本
要让每个line元素的material都是独立的对象,你需要给每个元素创建一个materialStd的副本,而不是直接引用它。常见的方法有这几种:
对象展开运算符(推荐,ES6+)
用{...materialStd}快速创建一个浅拷贝的新对象:var obj = { id: 0, line: [ { id: 1, material: {...materialStd} }, { id: 2, material: {...materialStd} }, { id: 3, material: {...materialStd} } ] }Object.assign()
用Object.assign({}, materialStd)把原对象的属性复制到新空对象里:var obj = { id: 0, line: [ { id: 1, material: Object.assign({}, materialStd) }, { id: 2, material: Object.assign({}, materialStd) }, { id: 3, material: Object.assign({}, materialStd) } ] }深拷贝(针对嵌套对象)
如果你的materialStd里面还有嵌套的对象,上面的浅拷贝就不够了,这时候可以用JSON.parse(JSON.stringify(materialStd))做深拷贝(注意:这个方法不能拷贝函数、undefined、Symbol等特殊值):var obj = { id: 0, line: [ { id: 1, material: JSON.parse(JSON.stringify(materialStd)) }, { id: 2, material: JSON.parse(JSON.stringify(materialStd)) }, { id: 3, material: JSON.parse(JSON.stringify(materialStd)) } ] }
用上面的方法修改后,每个line元素的material都是独立的对象,你修改其中一个的flow属性,其他的就不会跟着变啦!
内容的提问来源于stack exchange,提问作者Pierre

