为什么new Map也被垃圾回收了?

javascript中,如下代码,为何在car1=null之后,carMap.get(car1)的结果是undefined?我觉得应该依然是Corolla,因为如果是WeakMap的话,那应该是undefined,但实际是new Map(),依然会触发垃圾回收吗?为什么?

let carMap = new Map();
let car1 = { brand: 'Toyota' };
let car2 = { brand: 'Honda' };
carMap.set(car1, 'Corolla');
carMap.set(car2, 'Civic');
console.log(carMap.get(car1)); // 输出: Corolla  正常
console.log(carMap.get(car2)); // 输出: Civic   正常

car1 = null;

console.log(carMap.get(car1)); // 问题点:为什么会输出undefined?
console.log(carMap.get(car2)); // 输出: Civic  正常
阅读 1.7k
avatarAI BotBETA

在JavaScript中,Map 对象存储的是键值对,其中键和值都可以是任何类型。然而,Map 并不阻止其键(或值)被垃圾回收。当没有其他引用指向一个对象时,该对象就可能被垃圾回收机制回收。

在你的代码中,car1 是一个指向 { brand: 'Toyota' } 对象的引用。当你将 car1 设置为 null 时,你就断开了这个引用,这意味着没有其他变量或对象再引用 { brand: 'Toyota' } 这个对象了。因此,这个对象就变成了一个垃圾,可以被JavaScript的垃圾回收机制回收。

当垃圾回收机制回收了这个对象后,carMap 中原本以 { brand: 'Toyota' } 为键的条目实际上已经失去了它的键。因此,当你尝试使用 carMap.get(car1) 获取这个条目时,由于键已经被回收,所以返回的结果是 undefined

这并不取决于你使用的是 Map 还是 WeakMapWeakMap 的特点是它只接受对象作为键,并且如果键对象没有其他引用,那么该键和对应的值就会自动从 WeakMap 中删除。而 Map 则不会这样,即使键对象被回收,Map 中仍然会保留一个空白的条目。

所以,你的观察是正确的,carMap.get(car1) 返回 undefined 是因为 { brand: 'Toyota' } 这个对象已经被垃圾回收了,而不是因为 carMapWeakMap

3 个回答

并不是GC的问题,而是楼上说的 carMap.get(null) 的问题。
你期望的是 car1 变更为了 null 那么我给 carMap 的设置的 key 也会变成 null?但其实并不会。这点可以从简单的代码例子中看到:

let carMap = new Map();
let car1 = { brand: 'Toyota' };
let car2 = { brand: 'Honda' };
carMap.set(car1, 'Corolla');
carMap.set(car2, 'Civic');
carMap.get(car1);
// Corolla
carMap.get(car2);
// Civic

car1 = null;
carMap
// Map { {…} → "Corolla", {…} → "Civic" }
//   size: 2
//   <entries>
//     0: Object { brand: "Toyota" } → "Corolla"
//     1: Object { brand: "Honda" } → "Civic"

所以你在使用 carMap.get(car1) 时并不会获得期望的 Corolla 输出。


这部分就和你给对象的操作有关系了。当你将一个新的对象赋值给 car1 这个变量,那么变量 car1 将指向新对象的内存地址。而不是原来的内存地址了。

如果你要修改 car1 这个变量的值而不去修改这个变量的指向,那么你应该操作变量 car1,而不是直接给变量 car1 赋值一个新的值 👇

let carMap = new Map();
let car1 = { brand: 'Toyota' };
let car2 = { brand: 'Honda' };
carMap.set(car1, 'Corolla');
carMap.set(car2, 'Civic');
carMap.get(car1);
// Corolla
carMap.get(car2);
// Civic

car1.value = 'test';
carMap.get(car1);
// Corolla

补充一个简易的Demo来说明赋值操作的区别:

let obj1 = { name: 'John' };
let obj2 = obj1;

obj2.name = 'Jane'; // 这将修改 obj1 的 name 属性
console.log(obj1.name); // 输出 'Jane'

obj2 = { name: 'Bob' }; // 这将不会修改 obj1,因为 obj2 现在指向一个新的对象
console.log(obj1.name); // 输出 'Jane'

相关阅读

javascript - Using Array objects as key for ES6 Map - Stack Overflow
24.1.3.6 Map.prototype.get (key) | ECMAScript® 2025 Language Specification
Object.is() - JavaScript | MDN

image.png

你是不是想多了……这跟 GC 啥关系也没有……

这不就是直接 carMap.get(null) 么?不输出 undefined 还能输出什么?

断点一下就能知道,Map还是那个Map,只是Key为null了而已。

image.png

推荐问题
宣传栏