闭包是什么?内存泄漏是什么?内存泄漏的场景以及解决方式

90 阅读2分钟

闭包(Closure)
闭包是指函数能够访问并记住其词法作用域外的变量,即使外部函数已执行完毕。例如:

function outer() {
  const name = "Alice";
  function inner() {
    console.log(name); // 访问外部作用域的变量
  }
  return inner;
}
const closure = outer();
closure(); // 输出 "Alice"

闭包可能导致内存泄漏的核心原因是:如果闭包长期持有对大对象或DOM元素的引用,这些资源无法被垃圾回收。


内存泄漏(Memory Leak)
内存泄漏是指程序中已不再需要的内存未能被释放,导致内存占用持续增长,最终可能引发性能问题或崩溃。


JS中常见的内存泄漏场景

  1. 意外的全局变量
    function leak() {
      leakedVar = "意外全局变量"; // 未使用 let/const/var
      this.globalVar = "this指向全局(非严格模式)";
    }
    
  2. 未清理的定时器或回调
    const intervalId = setInterval(() => {}, 1000);
    // 忘记调用 clearInterval(intervalId)
    
  3. 残留的DOM引用
    const elements = {
      button: document.getElementById("myButton"),
    };
    // 即使从DOM中移除元素,elements.button仍持有引用
    
  4. 闭包不当使用
    function createHeavyClosure() {
      const bigData = new Array(1000000).fill("*");
      return () => bigData; // 闭包长期持有大数据引用
    }
    const holdData = createHeavyClosure();
    
  5. 未移除的事件监听
    window.addEventListener("resize", handleResize);
    // 组件销毁时未调用 removeEventListener
    

JS内存泄漏的解决方式

  1. 避免意外全局变量
    使用严格模式("use strict"),强制声明变量。
  2. 手动释放资源
    • 定时器:用 clearInterval/clearTimeout
    • DOM引用:使用后置为 nullelement = null)。
  3. 及时解绑事件监听
    // Vue/React组件销毁时
    beforeUnmount() {
      window.removeEventListener("resize", handleResize);
    }
    
  4. 谨慎使用闭包
    确保闭包不长期持有不必要的大对象,必要时手动解除引用。
  5. 使用弱引用(WeakMap/WeakSet)
    const weakMap = new WeakMap();
    let key = { id: 1 };
    weakMap.set(key, "data");
    key = null; // WeakMap中的引用会自动释放
    
  6. 工具检测
    • Chrome DevTools 的 Memory 面板(通过 Heap Snapshot 分析内存占用)。
    • performance.memory API 监控内存变化。

总结
闭包是JS的核心特性,但需注意其引用链;内存泄漏的关键在于“无用资源的引用未被释放”。通过规范代码、及时清理和工具分析,可有效避免泄漏问题。