兩個在函數內部創建的對象 a 和 b 相互引用(a.b = b; b.a = a;),函數執行結束後,這兩個對象是否會被垃圾回收器(GC)回收?
會被回收。 現代 JavaScript 引擎(V8、SpiderMonkey、JavaScriptCore 等)均採用標記-清除算法,而非引用計數。只要對象從 GC Roots(全局對象、調用棧等)不可達,無論內部是否存在循環引用,都會被標記為可回收。
(function() {
var a = {};
var b = {};
a.b = b;
b.a = a;
})();
a、b 在函數作用域內創建,形成循環引用。a、b 無任何外部變量引用。window(全局對象)出發,無法到達 a 或 b。var a = {};
var b = {};
a.b = b;
b.a = a;
// 此時 a、b 掛載在 window 上,GC Roots 可達,不會被回收
早期 IE(IE6/7)的 DOM/BOM 對象使用 COM 組件實現,採用引用計數機制。循環引用導致計數永不歸零,造成內存洩漏。但現代瀏覽器(含 IE9+)JS 引擎已全部改用標記-清除,此問題不復存在。
element.onclick = null; clearInterval(timer);window,使用 IIFE 或模塊化(ESM/CommonJS)隔離作用域。函數內部的循環引用對象一定會被回收,關鍵在於「是否可從 GC Roots 到達」。理解作用域鏈與垃圾回收機制,是寫出高性能、無洩漏 JavaScript 代碼的基石。