es6 map

es6 map
 
 
 
 
来自网络的快速搜索结果:
Map - JavaScript - MDN Web Docs - Mozilla
The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.
MDN Web Docs·https://developer.mozilla.org
JavaScript Maps - W3Schools
Well organized and easy to understand Web building tutorials with lots of examples of how to use HTML, CSS, JavaScript, SQL, Python, PHP, Bootstrap, Java, XML and more.
W3Schools·https://www.w3schools.com
在 JavaScript (ES6) 中,Map 是一种全新且非常强大的键值对(Key-Value)数据结构。
很多初学者容易把它和普通的**对象(Object)**搞混。简单来说:普通对象的键只能是字符串或 Symbol,而 Map 的键可以是任何类型(包括对象、函数、数字、甚至另一个 Map)。

🛠️ 1. Map 的基础增删改查 API
Map 的操作不使用普通的 .[] 语法,而是有一套标准的内置方法:
javascript
// 1. 初始化一个空 Map
const myMap = new Map();

// 2. 增/改:使用 .set(key, value)
myMap.set('name', '马良');
myMap.set(123, '数字键'); // 💡 键可以是数字类型

const objKey = { id: 1 };
myMap.set(objKey, '对象键'); // 💡 键甚至可以是一个对象

// 3. 查:使用 .get(key)
console.log(myMap.get('name'));   // 输出: 马良
console.log(myMap.get(objKey));   // 输出: 对象键

// 4. 判:使用 .has(key) 检查键是否存在
console.log(myMap.has('name'));   // 输出: true
console.log(myMap.has('age'));    // 输出: false

// 5. 量:使用 .size 获取键值对总数(注意:不是 length 属性)
console.log(myMap.size);          // 输出: 3

// 6. 删:使用 .delete(key) 移除某一项
myMap.delete(123);

// 7. 清:使用 .clear() 清空所有数据
// myMap.clear();
请谨慎使用此类代码。

🔄 2. Map 的遍历方式
Map 原生保持键值对的插入顺序,且完美支持 for...of 循环和 forEach
javascript
const userMap = new Map([
  ['id', 99],
  ['username', 'maliang']
]);

// 💡 方式 A:直接遍历解构(最常用、最优雅 ✨)
for (const [key, value] of userMap) {
  console.log(`${key} => ${value}`);
}

// 💡 方式 B:使用 forEach
userMap.forEach((value, key) => {
  console.log(key, value);
});

// 💡 方式 C:只遍历键(.keys())或只遍历值(.values())
for (const key of userMap.keys()) {
  console.log(key);
}
请谨慎使用此类代码。

🥊 3. 核心对比:Map vs Object (普通对象)
在现代前端开发中,该怎么选?看下面这个直观的对比表:
特性普通对象 ObjectES6 Map
键的类型 只能是字符串、Symbol 可以是任意类型(数字、对象、函数等)
键的顺序 顺序比较复杂(数字会升序、字符串按插入等) 严格保持插入时的顺序
获取大小 必须通过 Object.keys(obj).length 手动算 直接读取 .size 属性,时间复杂度为 O(1)
迭代支持 不能直接 for...of,需先用 Object.entries 转换 原生支持 for...of 和解构遍历
性能表现 频繁执行增删操作时,性能一般 在涉及频繁增删键值对的场景下,性能表现更好

🚀 4. 与其他类型的相互转换
💡 A. Map 转为数组 (使用扩展运算符 ...)
javascript
const myMap = new Map([['a', 1], ['b', 2]]);
const arr = [...myMap]; 
// 得到二维数组: [['a', 1], ['b', 2]]
请谨慎使用此类代码。
💡 B. Map 转为普通对象 (ES2019+ 语法)
javascript
const myMap = new Map([['name', '马良'], ['age', 18]]);
const obj = Object.fromEntries(myMap);
// 得到对象: { name: '马良', age: 18 }
请谨慎使用此类代码。

你目前在接触 ES6 Map,是为了解决 Koa / Node.js 内存数据缓存 的问题,还是在前端进行 大量数据的复杂查询、去重或性能优化?如果需要,我可以为你演示如何利用 Map 实现高效率的 两数之和(力扣算法最底层优化) 或者写一个 内存缓存服务类。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
weakmap
 
 
 
 
在 JavaScript (ES6) 中,WeakMapMap 的一个特殊兄弟版本。它最大的核心价值在于解决内存泄漏问题。
简单来说:WeakMap 里的键(Key)必须是对象,并且它对这些对象是“弱引用”的。如果这个对象在外界没有其他地方引用了,垃圾回收机制(GC)就会自动把它从内存里杀掉,即使它还在 WeakMap 里!

🥊 1. 核心区别:WeakMap vs Map
特性MapWeakMap
键的类型 任意类型(数字、字符串、对象等) 只能是对象(Object)(或特定环境下的非注册 Symbol)
引用类型 强引用(只要 Map 在,对象就不会被回收) 弱引用(不阻碍垃圾回收,容易随时被自动销毁)
可遍历性 可遍历(有 size, forEach, keys() 等) 不可遍历(没有任何遍历 API,也无法获取大小)

🛠️ 2. WeakMap 的基础 API(极简)
因为它的键值对随时可能被垃圾回收车“悄悄运走”,所以它不支持任何遍历和大小计算(没有 .size,没有 .clear(),没有 forEach)。它只有 4 个基础方法:
javascript
// 1. 初始化
const wm = new WeakMap();

let user = { name: "马良" };
const info = { role: "admin" };

// 2. 增/改:.set() —— 💡 键必须是对象!
wm.set(user, info); 

// wm.set('name', '张三'); // ❌ 报错!TypeError: Invalid value used as weak map key

// 3. 查:.get()
console.log(wm.get(user)); // 输出: { role: "admin" }

// 4. 判:.has()
console.log(wm.has(user)); // 输出: true

// 5. 删:.delete()
wm.delete(user);
请谨慎使用此类代码。

💡 3. 灵魂一问:什么是“弱引用”?(防内存泄漏原理)
我们用一段伪代码来看它怎么防止内存泄漏:
❌ 使用普通 Map 的情况:
javascript
let obj = { data: "大量数据" };
const myMap = new Map();

myMap.set(obj, "这是备注信息");

obj = null; // 💡 我们以为释放了 obj 的内存
// 结果:由于 myMap 还强引用着那个对象,垃圾回收不敢回收它。
// 必须手动 myMap.delete(obj),否则该对象会一直死锁在内存中,造成内存泄漏!
请谨慎使用此类代码。
使用 WeakMap 的情况:
javascript
let obj = { data: "大量数据" };
const wm = new WeakMap();

wm.set(obj, "这是备注信息");

obj = null; // 💡 我们释放了 obj
// 结果:垃圾回收机制一看,外界没人引用 obj 了,WeakMap 里的引用是“弱引用”,直接无视。
// 在下一次垃圾回收时,obj 占据的庞大内存就会被完美自动释放!
请谨慎使用此类代码。

🚀 4. 经典应用场景
在现代前端(如 Vue3 源码)和 Node.js(如 Koa 插件开发)中,WeakMap 有两大王牌舞台:
场景 A:往 DOM 节点上绑定额外数据(前端经典)
当你在网页上选中一个 HTML 按钮,想存一些跟它业务相关的数据:
javascript
const element = document.getElementById('my-button');
const buttonData = new WeakMap();

// 把 DOM 节点当成键
buttonData.set(element, { clickedCount: 0 });

// 当这个按钮被用户或者路由切掉、从页面删除时(element 销毁)
// buttonData 里对应的缓存数据也会瞬间被连带无缝回收,绝不占用内存!
请谨慎使用此类代码。
场景 B:Vue 3 响应式原理(追踪依赖)
Vue 3 的 reactive 核心底层就是用 WeakMap 来存储原始对象和 Proxy 代理对象之间的映射关系的:
javascript
// Vue 3 内部伪代码大致逻辑
const targetMap = new WeakMap(); // 键是用户传入的原始对象

function track(target, key) {
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  // ... 收集依赖
}
请谨慎使用此类代码。
这样做能保证,一旦用户的组件销毁、原始数据对象被扔掉,整个响应式的依赖追踪树也会跟着自动在内存中人间蒸发,保证了长生命周期应用的极端稳定。
你目前在研究 WeakMap,是在开发 Node.js 插件/轻量级缓存,还是在手写一些类似 Vue 的前端数据响应式逻辑?如果感兴趣,我可以为你写一个利用 WeakMap 实现的 私有属性类(Private Properties) 封装结构。

posted on 2026-09-21 14:07  漫思  阅读(6)  评论(0)    收藏  举报

导航