【前端每天一题】第 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 题:前端性能优化(重排/重绘、懒加载、打包优化)

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

相关推荐
LYFlied8 小时前
边缘智能:下一代前端体验的技术基石
前端·人工智能·ai·大模型
1024小神8 小时前
用css的clip-path裁剪不规则形状的图片展示
前端·css
铅笔侠_小龙虾8 小时前
Flutter 组件层级关系
前端·flutter·servlet
梵得儿SHI8 小时前
Vue 高级特性:渲染函数与 JSX 精讲(h 函数语法、JSX 在 Vue 中的应用)
前端·javascript·vue.js·jsx·模板语法·渲染函数·底层视图生成机制
GGGG寄了8 小时前
CSS——文字控制属性
前端·javascript·css·html
菜鸟茜8 小时前
ES6核心知识解析01:什么是ES6以及为什么需要ES6
前端·javascript·es6
C澒9 小时前
FE BLL 架构:前端复杂业务的逻辑治理方案
前端·架构·前端框架·状态模式
止观止9 小时前
拒绝“都是 string”:品牌类型与领域驱动设计 (DDD)
前端·typescript
芸简新章9 小时前
微前端:从原理到实践,解锁复杂前端架构的模块化密码
前端·架构
pusheng20259 小时前
燃料电池电化学传感器在硫化物固态电池安全监测中的技术优势解析
前端·人工智能·安全