为何常量defaultMap会被修改?如何正确实例化带默认值的Map?
为什么我的常量默认对象会被意外修改?如何解决?
问题场景
我定义了一个带默认值的常量对象:
const defaultMap: MapType = { val1: 0, val2: 0, };
接着在React的useEffect中尝试创建多个基于这个默认对象的实例,遍历数组修改它们的属性后,发现原本的defaultMap被意外修改了:
const useMaps = () => { useEffect(() => { let map1 = defaultMap; let map2 = defaultMap; let map3 = defaultMap; console.log(defaultMap) // 预期输出{val1:0, val2:0},但实际已被修改 ['val1', 'val2'].forEach((arrayVal) => { map1[arrayVal] = 1 map2[arrayVal] = 2 map3[arrayVal] = 3 }); // 用map1、map2、map3设置状态 }) }
原因分析
- JavaScript中对象是引用类型,
const关键字仅保证变量本身的引用不可被重新赋值,但它指向的对象内容是可以修改的。 - 执行
let map1 = defaultMap时,并没有创建新的对象,只是让map1、map2、map3都指向了defaultMap所在的内存地址。这三个变量本质上是同一个对象的不同引用,修改它们的属性,其实就是直接修改defaultMap本身。
解决方案
需要为每个map创建独立的对象副本,避免共享内存引用:
1. 浅拷贝(适用于无嵌套的简单对象)
- 使用扩展运算符:
let map1 = {...defaultMap}; let map2 = {...defaultMap}; let map3 = {...defaultMap}; - 使用
Object.assign:let map1 = Object.assign({}, defaultMap); let map2 = Object.assign({}, defaultMap); let map3 = Object.assign({}, defaultMap);
2. 深拷贝(适用于含嵌套结构的对象)
如果defaultMap包含嵌套对象或数组,浅拷贝只会复制外层引用,内层结构仍会共享,此时需要深拷贝:
- 使用
JSON.parse(JSON.stringify(defaultMap))(注意:无法处理函数、Symbol等特殊类型):let map1 = JSON.parse(JSON.stringify(defaultMap)); - 自定义深拷贝函数或使用第三方工具(如Lodash的
_.cloneDeep):import _ from 'lodash'; let map1 = _.cloneDeep(defaultMap);
内容的提问来源于stack exchange,提问作者timmy
相关产品推荐
相关产品推荐

