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 正常
断点一下就能知道,Map还是那个Map,只是Key为null了而已。
你是不是想多了……这跟 GC 啥关系也没有……
这不就是直接 carMap.get(null)
么?不输出 undefined 还能输出什么?
并不是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);// CorollacarMap.get(car2);// Civiccar1 = 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);// CorollacarMap.get(car2);// Civiccar1.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
在JavaScript中,Map
对象存储的是键值对,其中键和值都可以是任何类型。然而,Map
并不阻止其键(或值)被垃圾回收。当没有其他引用指向一个对象时,该对象就可能被垃圾回收机制回收。
在你的代码中,car1
是一个指向 { brand: 'Toyota' }
对象的引用。当你将 car1
设置为 null
时,你就断开了这个引用,这意味着没有其他变量或对象再引用 { brand: 'Toyota' }
这个对象了。因此,这个对象就变成了一个垃圾,可以被JavaScript的垃圾回收机制回收。
当垃圾回收机制回收了这个对象后,carMap
中原本以 { brand: 'Toyota' }
为键的条目实际上已经失去了它的键。因此,当你尝试使用 carMap.get(car1)
获取这个条目时,由于键已经被回收,所以返回的结果是 undefined
。
这并不取决于你使用的是 Map
还是 WeakMap
。WeakMap
的特点是它只接受对象作为键,并且如果键对象没有其他引用,那么该键和对应的值就会自动从 WeakMap
中删除。而 Map
则不会这样,即使键对象被回收,Map
中仍然会保留一个空白的条目。
所以,你的观察是正确的,carMap.get(car1)
返回 undefined
是因为 { brand: 'Toyota' }
这个对象已经被垃圾回收了,而不是因为 carMap
是 WeakMap
。
问题内容: 什么是JavaScript垃圾回收?为了编写更好的代码,对于Web程序员来说,了解JavaScript垃圾回收有什么重要意义? 问题答案: 从该页面引用: JScript使用了非世代的标记清除垃圾收集器。它是这样的: 每个“范围内”的变量都称为“清除剂”。清道夫可以指数字,对象,字符串等。我们维护一个清道夫列表- 变量进入作用域时将移入scav列表,超出范围时将其移出scav列表。 垃
垃圾回收 我们对生产中花了很多时间来调整垃圾回收。垃圾回收的关注点与Java大致相似,尽管一些惯用的Scala代码比起惯用的Java代码会容易产生更多(短暂的)垃圾——函数式风格的副产品。Hotspot的分代垃圾收集通常使这不成问题,因为短暂的(short-lived)垃圾在大多情形下会被有效的释放掉。 在谈GC调优话题前,先看看这个Attila的报告,它阐述了我们在GC方面的一些经验。 Scal
对于开发者来说,JavaScript 的内存管理是自动的、无形的。我们创建的原始值、对象、函数……这一切都会占用内存。 当我们不再需要某个东西时会发生什么?JavaScript 引擎如何发现它并清理它? 可达性(Reachability) JavaScript 中主要的内存管理概念是 可达性。 简而言之,“可达”值是那些以某种方式可访问或可用的值。它们一定是存储在内存中的。 这里列出固有的可达值的
垃圾收集,引用计数,显式分配 和所有的现代语言一样,OCaml提供垃圾收集器,所以你不用像C/C++一样显式地分配和释放内存。 JWZ在他的文章 "Java sucks" rant(Java蛋疼(怒)!): 第一个好家伙是Java没有 free()。其他的都没有所谓了。这几乎掩盖了所有的缺点,不管有多糟糕, 这个有点让后续文档基本都没有意义了,但是...(译注:但是啥大家自己看吧) OCaml的垃
主要内容:垃圾回收器函数,实例Lua 采用了自动内存管理。 这意味着你不用操心新创建的对象需要的内存如何分配出来, 也不用考虑在对象不再被使用后怎样释放它们所占用的内存。 Lua 运行了一个垃圾收集器来收集所有死对象 (即在 Lua 中不可能再访问到的对象)来完成自动内存管理的工作。 Lua 中所有用到的内存,如:字符串、表、用户数据、函数、线程、 内部结构等,都服从自动管理。 Lua 实现了一个增量标记-扫描收集器。 它使用
主要内容:1 什么是Java 垃圾回收,2 Java 垃圾回收的优势,3 如何取消对象引用,4 finalize()方法,5 gc()方法,6 Java 垃圾回收的例子1 什么是Java 垃圾回收 在Java中,垃圾意味着未引用的对象。 垃圾回收是自动回收运行时未使用的内存的过程。换句话说,这是销毁未使用对象的一种方法。 我们在C语言中使用free() 函数,在C ++中使用delete()。但是,在Java中它是自动执行的。因此,java提供了更好的内存管理。 2 Java 垃圾回收的优势 它