JavaScript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

一、闭包的本质定义

闭包是通过函数嵌套 函数来实现的。内部函数可以访问外部函数的变量,既是外部函数已经执行完毕。

function outer() {
  let secret = 123;
  return function inner() {
    console.log(secret); // 访问外部变量
  };
}
const fn = outer();
fn(); // 123(仍能访问已销毁的outer作用域)

二、核心运行机制

  1. 作用域链保留:函数定义时捕获外层环境引用
  2. 生命周期延续:内部函数存在则外部变量不回收
  3. 动态访问:闭包变量可实时获取最新值

 三,闭包的应用场景

1. 模块模式

const counter = (() => {
  let count = 0;


  return {
    add: () => ++count,
    get: () => count,
    reset: () => count = 0
  };
})();


counter.add();
console.log(counter.get()); // 1

2. 私有变量封装

function Person(name) {
  let _age = 0;


  return {
    getName: () => name,
    setAge: age => _age = age,
    getInfo: () => `${name}(${_age})`
  };
}


const p = Person('Alice');
p.setAge(25);
console.log(p.getInfo()); // Alice(25)

3. 循环陷阱解决方案

for(var i=0; i<3; i++) {
  (function(j) {
    setTimeout(() => console.log(j), 100);
  })(i);
}
// 输出 0 1 2(不用闭包会输出3次3)

四,性能优化技巧

// 优化前:每次调用创建新闭包
function heavy() {
  const data = new Array(1000000);
  return () => data.length;
}


// 优化后:复用闭包
const light = (() => {
  const cache = new Map();
  return key => {
    if(!cache.has(key)) {
      cache.set(key, new Array(1000000));
    }
    return cache.get(key).length;
  }
})();

箭头函数简化闭包:

const createAdder = x => y => x + y;
const add5 = createAdder(5);
console.log(add5(3)); // 8

五,注意

  • 内存占用
  • 闭包可能会
  • 导致一些内存占用问题,
  • 特别是当他们引用大量数据时。
  • 确保适当的管理这些引用

避免内存泄漏

  • 垃圾回收
  • 现代JavaScript引擎(如V8)
  • 会尝试优化闭包的内存管理,
  • 但在编写代码时 仍需注意避免不必
  • 要的闭包使用
  • 性能
  • 在某些情况下,
  • 频繁使用闭包可能会轻微影响性能,
  • 尤其是在循环或频繁调用时。尽量避免不
  • 必要的闭包可以提高性能