JavaScript服务运行时为何原常量对象被意外修改,如何规避?
问题解答
根本原因
Object.assign是浅拷贝,仅会复制对象的第一层属性,不会递归复制深层的引用类型属性。你执行Object.assign({}, dataSchema())的时候,新创建的dataScheme对象的project属性,仍然和原objData的project属性指向同一个内存地址,修改dataScheme.project下的属性本质就是修改原objData的内容。- 你的
dataSchema函数每次都返回同一个全局objData的引用,多次调用拿到的都是同一个根对象的引用,第一次修改后原对象就被污染了,后续调用拿到的都是被修改过的值。
解决方案
方案1(优先推荐):每次调用dataSchema时返回全新的schema对象
不要复用全局的objData,直接在函数内生成新对象,从根源避免引用共享,无额外性能损耗:
const dataSchema = () => { return { project: { name: '', age: 0, subProject: { name: '', age: 0 } } } }
修改后无需改动其他逻辑,即可正常运行。
方案2:对schema做深拷贝
如果一定要复用全局的schema对象,把原有的浅拷贝逻辑替换为深拷贝即可:
const mappingData1 = (data) => { try { // 用JSON序列化反序列化实现深拷贝,适用于schema无函数、Symbol、循环引用的场景 const dataScheme = JSON.parse(JSON.stringify(dataSchema())) dataScheme.project.name = data.name; dataScheme.project.age = data.age; return dataScheme; }catch(err){ return err; } } // mappingData2做相同的拷贝逻辑修改即可
如果项目已经引入了lodash,也可以直接用_.cloneDeep(dataSchema())实现深拷贝。
方案3:逐层展开创建新对象
适合需要精细控制拷贝层级的场景,性能比通用深拷贝更高:
const dataScheme = { ...dataSchema(), project: { ...dataSchema().project, subProject: { ...dataSchema().project.subProject } } }
内容的提问来源于stack exchange,提问作者masdap
相关产品推荐
相关产品推荐

