JavaScript有哪些可变键值结构?如何实现Map引用同步更新?
问题解答
测试案例差异澄清
你观察到的普通对象和Map的表现差异,本质是两次测试的操作逻辑完全不同,和结构本身无关:
你在普通对象测试中是修改已有引用指向对象的内部属性,没有替换cache.John的引用指向;而Map测试中是直接调用set方法给同一个key赋值了全新的对象,等价于在普通对象中执行cache.John = {lastName: "bar"},这种操作下普通对象也不会同步之前拿到的引用:
const cache = {}; cache.John = {lastName:"foo"} const John = cache.John; // 直接替换整个属性的引用,而非修改内部属性 cache.John = {lastName: "bar"}; console.log(John); // 输出 { lastName: 'foo' },和Map表现完全一致
问题1:实现Map值更新后已有引用同步的方案
有两种常用实现方案:
方案1:修改原有对象属性,不替换整个引用
只要不调用set传入新对象,而是取出已有对象修改内部属性,即可实现同步,和普通对象的操作逻辑完全一致:
const cache = new Map(); cache.set("John",{lastName:"foo"}); const John = cache.get("John"); // 取出已有对象修改内部属性,不替换整个值 cache.get("John").lastName = "bar"; console.log(John); // 输出 { lastName: 'bar' }
方案2:容器层包装,适合必须替换整个值的场景
如果业务逻辑需要完整替换存储的对象,可以给存储值套一层统一的容器,所有访问都通过容器的属性获取实际值,替换时仅修改容器的属性即可实现所有引用同步:
const cache = new Map(); // 所有值都套在value字段的容器中 cache.set("John", { value: {lastName:"foo"} }); const JohnRef = cache.get("John"); // 替换时仅修改容器的value属性,容器本身的引用不变 cache.get("John").value = {lastName:"bar"}; console.log(JohnRef.value); // 输出 { lastName: 'bar' }
问题2:JavaScript其他可用的可变键值结构
原生内置的可变键值结构除了Map还有以下几种:
- 普通对象(
Object):最通用的键值结构,键仅支持字符串、Symbol类型,存在原型链默认键冲突的风险,适合键类型固定、增删操作频率低的场景 WeakMap:弱引用类型的键值结构,键必须为引用类型(对象、函数等),当键的引用没有其他地方使用时会被自动垃圾回收,适合做临时对象的关联缓存,不会产生内存泄漏- 如需响应式同步的能力,可通过
Proxy对普通对象或Map做自定义封装,拦截写入操作实现全局变更通知,不属于原生内置结构。
内容的提问来源于stack exchange,提问作者nedas1234
相关产品推荐
相关产品推荐

