如何让存入数组的JavaScript对象保持不可变?解决引用同步问题
解决对象引用导致数组记录跟随原变量变化的问题
问题核心在于:JavaScript中对象(包括自定义类的实例)是引用类型——直接存储或错误复制时,数组元素和原变量指向同一块内存地址,原对象修改后,数组内容也会跟着变化。要避免这种情况,你需要创建原对象的独立副本,而非存储引用。
以下是针对你场景的可行方案:
方案1:给自定义类添加克隆方法
这是自定义类最适配的方式,在类中实现返回新实例的方法,确保存入数组的是独立对象:
class dummy { constructor (val1, val2) { this.val1 = val1 this.val2 = val2 } // 新增克隆方法,返回全新的dummy实例 clone() { return new dummy(this.val1, this.val2) } } let data = [] let dummy1 = new dummy(1, 2) // 调用clone方法存入数组 data.push(dummy1.clone()) dummy1.val1 = 3 dummy1.val2 = 4 console.log(`${dummy1.val1}, ${dummy1.val2}`) // 输出:3, 4 console.log(`${data[0].val1}, ${data[0].val2}`) // 输出:1, 2
方案2:通过构造函数手动创建新实例
如果类的属性都是基本类型(数字、字符串、布尔等),直接用原实例的属性值创建新实例即可,就像你示例中写的那样(确保传入的是属性值而非对象本身):
class dummy { constructor (val1, val2) { this.val1 = val1 this.val2 = val2 } } let data = [] let dummy1 = new dummy(1, 2) // 用原实例的属性值创建新实例推入数组 data.push(new dummy(dummy1.val1, dummy1.val2)) dummy1.val1 = 3 dummy1.val2 = 4 console.log(`${dummy1.val1}, ${dummy1.val2}`) // 3, 4 console.log(`${data[0].val1}, ${data[0].val2}`) // 1, 2
注:如果类属性包含嵌套引用类型(比如对象、数组),这种浅拷贝方式仍会出现跟随变化的问题,此时需要用深拷贝。
方案3:深拷贝(适用于复杂嵌套对象)
如果实例包含嵌套的引用类型属性,可以用JSON.parse(JSON.stringify(xxx))实现深拷贝,但要注意这种方法不支持函数、Symbol、循环引用等场景:
class dummy { constructor (val1, val2) { this.val1 = val1 this.val2 = val2 } } let data = [] let dummy1 = new dummy(1, 2) // 深拷贝后转换为dummy实例存入数组 const copiedDummy = JSON.parse(JSON.stringify(dummy1)) data.push(new dummy(copiedDummy.val1, copiedDummy.val2)) dummy1.val1 = 3 dummy1.val2 = 4 console.log(`${dummy1.val1}, ${dummy1.val2}`) // 3, 4 console.log(`${data[0].val1}, ${data[0].val2}`) // 1, 2
另外你之前尝试的const关键字,仅保证变量本身的引用不变,无法冻结对象内部属性,因此对你的场景无效;如果要冻结对象内部属性可以用Object.freeze(),但会导致原对象也无法修改,显然不符合需求。
内容的提问来源于stack exchange,提问作者somebody1122
相关产品推荐
相关产品推荐

