【前端每天一题】第 23 题:闭包(Closure)与作用域链(详细 + 面试模板 + 速记卡)

好的,继续 第 25 题:闭包(Closure)与作用域链(详细 + 面试模板 + 速记卡)


第 25 题:闭包(Closure)与作用域链

闭包是前端面试必考题,几乎每家公司都会问。

我会用非常详细但清晰的方式讲解。


一、闭包是什么?

闭包 = 函数 + 其定义时的词法环境(外部变量)

简单说:
闭包让函数可以"记住"它定义时的外部变量,即使外部函数已经执行完毕。

比如:

scss 复制代码
function outer() {
  let count = 0;
  return function inner() {
    count++;
    console.log(count);
  };
}

const fn = outer();
fn(); // 1
fn(); // 2

即使 outer() 执行完,count 仍然能被访问,这就是闭包。


二、闭包形成的原因:词法作用域

JS 采用 词法作用域(静态作用域) ,作用域在函数定义时已经确定。

所以 inner 函数能访问 outer 的变量。

编译阶段就决定了作用域链,运行时不会改变。


三、闭包的用途(面试重点)

1. 创建私有变量

javascript 复制代码
function createCounter() {
  let num = 0;
  return {
    inc() { num++; },
    get() { return num; }
  }
}

2. 防抖 / 节流、缓存函数里面常用

vbnet 复制代码
function cache(fn) {
  const map = {};
  return function(key) {
    if (map[key]) return map[key];
    return map[key] = fn(key);
  };
}

3. 柯里化 Currying

css 复制代码
const add = a => b => a + b;

4. 模拟块级作用域(ES5 时代)

javascript 复制代码
for (var i = 0; i < 3; i++) {
  setTimeout((function(i){ 
    return function() { console.log(i) }
  })(i), 1000);
}

四、闭包的缺点(面试必问)

闭包会导致变量常驻内存,可能造成内存泄漏

例如:

javascript 复制代码
function test() {
  let data = new Array(100000).fill(0);
  return function() {
    console.log(data.length);
  }
}
const f = test();

data 一直无法释放,因为闭包引用它。


五、作用域链(Scope Chain)

作用域链 = 当前作用域 → 外部作用域 → 全局作用域

查变量是从内到外一层层查。

示例:

ini 复制代码
var a = 1;

function f1() {
  var b = 2;
  function f2() {
    var c = 3;
    console.log(a, b, c);
  }
  f2();
}
f1();

作用域链查找顺序:

csharp 复制代码
f2 → f1 → global

六、面试官常问三连

① 闭包是什么?

闭包是在函数创建时,把函数和它的词法作用域绑定在一起,使函数在外部作用域结束之后仍然能访问该作用域的变量。

② 闭包有什么用?

私有变量、缓存、柯里化、防抖节流内部状态、回调函数等。

③ 闭包有什么风险?

变量不会释放,容易造成内存泄漏,如不需要应置为 null 或使用块级作用域优化。


七、经典闭包题 --- 面试必考

❗例题:

css 复制代码
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}

输出?

复制代码
3 3 3

原因:

  • var 没有块级作用域
  • 三个回调共享同一个 i
  • 当执行回调时,i 已变为 3

改成 let:

css 复制代码
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}

输出:

复制代码
0 1 2

八、速记卡片

复制代码
闭包 = 函数 + 外部变量
作用:记住状态(私有变量、缓存)
关键:词法作用域决定作用域链
风险:内存泄漏(变量无法释放)

如果你准备好了,我可以继续 第 26 题:前端性能优化(重排/重绘、懒加载、打包优化)

说一句:"下一题"即可。

相关推荐
前端一课1 小时前
【前端每天一题】🔥第 22 题:HTTP vs HTTPS、TCP vs UDP 的区别
前端·面试
前端一课1 小时前
第 26 题:浏览器与 Node.js 的事件循环有什么区别?
前端·面试
前端一课1 小时前
【前端每天一题】🔥 第 24 题:Virtual DOM 中 diff 算法的核心流程(详细版
前端·面试
掘金012 小时前
根据提供的表格动态渲染多个表单,每个配置项包含 label、prop、type 和 placeholder 等属性。
前端
用户4445543654262 小时前
自定义viewgroup
前端
ohyeah2 小时前
用 Coze 打造你的教育智能客服:从想法到前端集成的完整实践
前端·coze·trae
雨雨雨雨雨别下啦2 小时前
【从0开始学前端】 Git版本控制系统
前端·git
前端一课2 小时前
【前端每天一题】 第 15 题:CSS 水平垂直居中高频方案(Flex / Grid / transform 等)
前端·面试
前端一课2 小时前
【前端每天一题】🔥 第 19 题:什么是重排(Reflow)和重绘(Repaint)?有什么区别?如何减少?
前端·面试