首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

JavaScript 循環引用對象會被垃圾回收嗎?閉包與作用域的關鍵區別

     編輯:程式設計疑難解答

問題核心

兩個在函數內部創建的對象 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;
})();
  1. 函數執行時,a、b 在函數作用域內創建,形成循環引用。
  2. 函數執行結束,作用域銷毀,a、b 無任何外部變量引用。
  3. GC 掃描時發現:從 window(全局對象)出發,無法到達 a 或 b。
  4. 判定為不可達對象,下次 GC 週期中回收內存。

對比:全局變量情況

var a = {};
var b = {};
a.b = b;
b.a = a;
// 此時 a、b 掛載在 window 上,GC Roots 可達,不會被回收

深度解析:為什麼舊版 IE 有問題?

早期 IE(IE6/7)的 DOM/BOM 對象使用 COM 組件實現,採用引用計數機制。循環引用導致計數永不歸零,造成內存洩漏。但現代瀏覽器(含 IE9+)JS 引擎已全部改用標記-清除,此問題不復存在。

實戰避坑指南

  • 閉包保留引用:若內部函數被外部引用(如事件回調、定時器),會攜帶外層作用域,導致對象長駐內存。需手動解綁:element.onclick = null; clearInterval(timer);
  • 全局變量污染:避免無意掛載到 window,使用 IIFE 或模塊化(ESM/CommonJS)隔離作用域。
  • WeakMap/WeakSet:緩存場景下優先使用弱引用容器,不阻礙 GC。

總結

函數內部的循環引用對象一定會被回收,關鍵在於「是否可從 GC Roots 到達」。理解作用域鏈與垃圾回收機制,是寫出高性能、無洩漏 JavaScript 代碼的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved