红宝书第六讲:作用域链与闭包:厨房里的调味料架原理

红宝书第六讲:作用域链与闭包:厨房里的调味料架原理

资料取自《JavaScript高级程序设计(第5版)》。 查看所有教程:红宝书学习大纲


一、什么是作用域链?(洋葱层级结构)

想象你在厨房做菜,每个调料瓶按使用频率由近到远摆放:

  1. 当前厨房台面:手边的盐、酱油 → 相当于函数内部变量(局部作用域)
  2. 冰箱里的辣椒酱:常用但稍远 → 外层函数的变量(父级作用域)
  3. 储藏室的大米:最远的储备 → 全局变量(全局作用域)

作用域链的查找顺序

javascript 复制代码
function 厨房() {
  const 盐 = "适量盐"; // 第二层作用域

  function 炒菜() {
    console.log(盐); // ✅ 能找到冰箱里的盐
    console.log(大米); // ✅ 能找到储藏室的大米
  }
  
  炒菜();
}

const 大米 = "5kg"; // 第三层(全局)
厨房();

二、闭包:私人调料罐

闭包就像你出门前把常用调料装进便携罐带走:

  • 定义:内部函数保留外部变量的引用,"保鲜"这部分变量的值。
  • 关键特点:即使外层函数已执行完毕,闭包仍然能访问其变量。

代码示例

javascript 复制代码
function 制盐机() {
  let 盐堆存量 = 1000;   // 盐堆存量被内部函数"锁住"

  return function 取盐(需要量) {
    盐堆存量 -= 需要量;  // 每次取盐减少存量
    console.log(`剩余盐量:${盐堆存量}g`);
  };
}

const 我的取盐动作 = 制盐机();
我的取盐动作(100);  // 剩余盐量:900g
我的取盐动作(200);  // 剩余盐量:700g
  • 分析制盐机()执行后,本应销毁的盐堆存量取盐函数保留,形成闭包[^3]。

三、闭包的两面性

益处

  1. 数据保护 :避免变量全局污染,如封装计数器:

    javascript 复制代码
    function 创建计数器() {
      let count = 0;
      return () => ++count; // 只能通过闭包修改
    }
    const 计数器 = 创建计数器();
    计数器(); // 1

潜在问题

  • 内存泄漏:如果闭包引用大型数据且未被释放,可能影响性能:

风险示例

javascript 复制代码
function 加载大数据() {
  const 大数据 = new Array(1000000).fill('🚗'); // 内存大户

  return function 处理函数() {
    // 即使不再需要大数据,闭包仍保留引用
  };
}
let 保存闭包 = 加载大数据();
保存闭包 = null; // ✅ 需手动解除引用

四、生活中的闭包场景

  1. 按钮点击统计:记录用户点击按钮次数。

  2. 接口请求防重复:闭包保存最后一次请求标识。

  3. 模块化开发 :借助IIFE(立即执行函数)封闭作用域:

    javascript 复制代码
    const 模块 = (function() {
      const 内部数据 = "私有";
    
      return {
        get数据: () => 内部数据
      };
    })();
    
    console.log(模块.get数据()); // '私有'

目录:总目录 上篇文章:红宝书第五讲:函数声明与表达式小白详解

总结与练习

  • 理解步骤:先画作用域层级 → 再看闭包如何抓取变量。
  • 练习:实现一个缓存计算结果的闭包函数。

重要提醒:闭包虽强大,但控制引用范围,避免内存包袱过重!

相关推荐
阿珊和她的猫1 小时前
v-scale-scree: 根据屏幕尺寸缩放内容
开发语言·前端·javascript
加班是不可能的,除非双倍日工资5 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi6 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip6 小时前
vite和webpack打包结构控制
前端·javascript
excel7 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国7 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼7 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy7 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT7 小时前
promise & async await总结
前端
Jerry说前后端7 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化