# 《剑指JavaScript——核心原理与应用实践》知识点全解 > AI生成|2026年10月29日|codebuddy|原书:尚硅谷教育《剑指JavaScript——核心原理与应用实践》,电子工业出版社,2023-04-01 > **我的阅读**:进度 100%|累计 5小时14分钟|开始 2024-04-19|最近 2024-05-08|读完 2024-05-08 **一句话总结**:用 ES5 与 ES6 融合的写法,把 JavaScript 从语法表象讲到执行机制(作用域、this、原型、闭包、内存),让"会写"变成"知道为什么这样写"。 **适合谁 / 前置知识**:适合零基础到能写页面交互、但被 `undefined`、`this`、`0.1+0.2`、闭包绕晕的初学者,以及从其他语言转来、需要补 JS 语义细节的人;前置只需 HTML/CSS 常识与基本编程概念。不适合已熟悉规范、想研究引擎实现或框架源码的读者——本书是入门到进阶的语法与原理通识,不涉及 TypeScript、工程化、框架原理。 ## 一、全书地图 | 章 | 主题 | 解决的核心问题 | 在全书中的位置 | |---|---|---|---| | 第1章 | 走进 JavaScript 世界 | 是什么、从哪来、跑在哪、怎么写第一行 | 建立语境,交代 ECMAScript/DOM/BOM 分工 | | 第2章 | 变量 | 三种声明方式如何取舍 | 语法起点,直接决定作用域理解 | | 第3章 | 基本数据类型 | 值有哪几种、怎么判断、怎么转换 | 数据层,是运算符与比较的前置 | | 第4章 | 运算符和表达式 | 表达式如何求值、优先级如何 | 操作数据的手段 | | 第5章 | 语句 | 控制流如何组织 | 把前四章串成程序 | | 第6章 | 函数(上) | 定义、参数、作用域、箭头函数 | 从"语句"升级到"抽象" | | 第7章 | 对象 | 创建、属性操作、原型链、内置对象 | 承接函数,进入对象模型 | | 第8章 | 函数(下) | IIFE、arguments、回调、递归、this、预解析、闭包、内存 | 原理密度最高处,回收前七章伏笔 | 逻辑主线:**语法外壳(1–5)→ 复用单元(6)→ 数据组织(7)→ 运行机制(8)**。第8章不是新知识,而是对第2、6、7章的解释器视角复盘:变量声明引出提升,函数引出 this 与闭包,对象引出原型与内存。所给目录止于第8章,简介提到的 BOM、DOM、AJAX、异步与更多 ES6 特性**章节位置待核对**,本笔记按主题归入"宿主环境与异步",不臆造编号。 还有两条贯穿全书的暗线,读的时候值得单独标出来:一是**"声明与赋值分离"**,从第2章的提升到第8章的预解析,本质是同一件事在不同粒度上的展开;二是**"引用与值"**,从第3章的原始类型、第7章的对象复制,一直延伸到第8章的内存管理,凡是"改了 A 结果 B 也变了"的困惑,几乎都能归到这条线上。抓住这两条线,八章内容就不再是并列的知识点,而是一条可以自己往前推的推理链。 ## 二、核心知识点 **1. JavaScript 的三层组成** 是什么:语言核心是 ECMAScript(语法、类型、语句、内置对象);DOM 是文档操作接口;BOM 是浏览器窗口、地址、历史、屏幕等接口。 为什么重要:分清"语言"与"宿主 API",才能解释为什么 Node 里没有 `document`、为什么 `setTimeout` 不在语言规范里。 怎么用:遇到不确定的 API 先问属于哪层——`map` 是语言,`localStorage` 是宿主。 常见误区:把 jQuery、Vue 当 JavaScript;把 DOM 操作当作语言内置能力。 **2. 严格模式** 是什么:脚本或函数首行写 `'use strict'`:未声明赋值报错、普通调用的 `this` 为 `undefined`、禁止删除变量、禁止 `with`、`arguments` 不与形参联动。 为什么重要:把静默失败变成显式报错;ES6 模块与 class 内部默认严格,是读现代代码的前提。 怎么用:新项目整体启用,老代码按函数粒度渐进启用。 常见误区:指令写在其他语句之后(不生效);以为函数内启用会污染全局。 **3. var / let / const 的差异** 是什么:`var` 函数作用域、提升并初始化为 `undefined`、可重复声明、挂全局对象;`let`/`const` 块级作用域、提升但不初始化(暂时性死区)、不可重复声明;`const` 约束绑定而非对象内容。 为什么重要:块级作用域直接消灭了"循环变量共享"这类经典 bug。 怎么用:默认 `const`,需重新赋值才 `let`,`var` 只用于老代码。 常见误区:认为 `const` 对象不可改;把死区理解成"没有提升";同一 `switch` 的不同 `case` 里重复声明同名 `let`。 **4. 数据类型与 typeof** 是什么:原始类型有 Number、String、Boolean、Undefined、Null、BigInt(ES6 另有 Symbol,书中位置待核对),其余都是 Object。 为什么重要:类型决定赋值是复制值还是复制引用,也决定比较结果。 怎么用:`typeof` 返回小写字符串;判 null 用 `=== null`,判数组用 `Array.isArray`,判 NaN 用 `Number.isNaN`。 常见误区:`typeof null === 'object'` 是历史遗留,不能当对象判断依据;`typeof []` 同样是 `'object'`。 **5. Number 的精度与 BigInt** 是什么:数字统一是双精度浮点,安全整数上限 2^53−1;`0.1 + 0.2 !== 0.3`;`NaN` 不等于自身;BigInt 用 `n` 后缀表示任意精度整数。 为什么重要:金额、ID、大数算错往往不是逻辑问题而是类型问题。 怎么用:金额以"分"为单位的整数运算,或转字符串/BigInt。 常见误区:用 `==` 判 NaN;BigInt 与 Number 直接混合运算(抛错);用浮点数做等值判断。 **6. 显式与隐式类型转换** 是什么:显式用 `Number()`、`parseInt/parseFloat`、`String()`、`Boolean()`;隐式发生在 `+`、`-`、`==`、`if` 等场景。假值只有 `false、0、-0、''、null、undefined、NaN`。 为什么重要:绝大多数"玄学 bug"来自隐式转换,而非语法写错。 怎么用:`Number('')` 得 0 而 `parseInt('12px')` 得 12;`+` 任一侧是字符串即拼接;统一用 `===`。 常见误区:以为 `[] == false` 是引擎 bug(实为转换规则);用 `!!` 判空数组(`[]` 为 true);依赖 `parseInt` 缺省基数。 **7. 运算符与优先级** 是什么:算术、赋值、比较、逻辑、条件、其他(`typeof`、`delete`、`,`、`?.`、`??`)。逻辑运算符返回操作数本身而非布尔值,且短路求值。 为什么重要:默认值、可选链、空值合并都建立在短路语义上。 怎么用:`a || b` 在 `a` 为假值时取 `b`;只想处理 `null/undefined` 用 `a ?? b`;字符串按 UTF-16 码元逐位比较,`'10' < '9'` 为 true。 常见误区:用 `||` 给可能为 `0` 或 `''` 的参数设默认值;不写括号硬记优先级。 **8. 语句与控制流** 是什么:`if/else`、`switch`、`for`、`while`、`do…while`、`break/continue/return`、循环嵌套。 为什么重要:控制流是算法骨架;`switch` 用全等比较,适合离散等值分支,`if` 适合区间与复合条件。 怎么用:`do…while` 保证至少执行一次;多层嵌套用标签跳转或提前 `return` 降深度。 常见误区:`switch` 漏写 `break` 造成穿透;`for` 中用 `var` 声明循环变量;缺少退出条件导致死循环。 **9. 函数、参数与 arguments** 是什么:声明式、表达式、箭头三种写法;形参与实参数量不匹配不报错;`arguments` 是类数组,箭头函数没有;ES6 提供默认参数、剩余参数、解构参数。 为什么重要:JS 没有传统重载,多态靠参数形态或配置对象模拟。 怎么用:参数多于三个改用对象;用 `...rest` 代替 `arguments` 拿真数组。 常见误区:在箭头函数里用 `arguments`(拿到外层);以为改 `arguments` 一定同步形参(严格模式不同步)。 **10. 作用域、作用域链与预解析** 是什么:作用域分全局、函数、块级;词法作用域在**定义时**确定;变量查找沿作用域链向外直至全局;预解析阶段 `var` 声明提升、函数声明整体提升且优先于变量。 为什么重要:它同时解释"函数为何能先调用后定义"和"为什么这里打印 undefined"。 怎么用:读代码先做提升推演,再按作用域链找变量来源。 常见误区:以为作用域由调用位置决定;以为函数表达式会整体提升;在块内写函数声明并期待跨块可用。 **11. this 的绑定规则** 是什么:默认绑定(严格模式 undefined,否则全局对象)、隐式绑定(`obj.fn()`)、显式绑定(`call/apply/bind`)、new 绑定、箭头函数的词法 this。优先级:new > 显式 > 隐式 > 默认。 为什么重要:回调丢失 this 是最常见的运行时错误之一。 怎么用:`const f = obj.method` 或把方法当回调传递时用 `bind`/箭头函数固定;箭头函数不用于需要动态 this 的方法。 常见误区:试图用 `call` 修改箭头函数的 this(无效);对象方法里嵌套普通函数,this 变成全局。 **12. 对象操作与 ES6 简写** 是什么:字面量、构造函数、`Object.create`;点/方括号访问;`delete` 只删自有可配置属性;`in` 查原型链,`hasOwnProperty` 只查自有;`Object.keys/values/entries/assign`;ES6 属性与方法简写、计算属性名、解构。 为什么重要:"自有/继承"之分是理解原型与遍历行为的钥匙。 怎么用:遍历自身属性用 `Object.keys`;合并配置用展开运算符(浅拷贝)。 常见误区:`delete` 数组元素留下空洞;把 `Object.assign` 当深拷贝;`for…in` 会枚举到继承的可枚举属性。 **13. 原型与原型链** 是什么:函数有 `prototype`,对象有内部原型(`__proto__` / `Object.getPrototypeOf`);读属性沿原型链查找,终点 `Object.prototype` 再到 `null`;`constructor` 指回构造函数;`instanceof` 检查原型链上是否存在目标原型。 为什么重要:JS 的复用与继承靠原型,class 只是语法糖。 怎么用:共享方法放 `prototype`;`Object.create(null)` 造无原型字典;用 `hasOwnProperty` 区分自有与继承。 常见误区:把 `prototype` 与 `__proto__` 混为一谈;直接改内置原型污染全局。 **14. 内置对象常用 API** 是什么:String(`slice/substring/substr`、`includes`、`split/join`、`trim`、`replace`、`padStart`)、Array(`push/pop`、`slice/splice`、`map/filter/reduce`、`forEach`、`sort`、`find`、`flat`)、Math、Date、JSON、RegExp。 为什么重要:业务代码八成在组合这些方法,选错即隐藏 bug。 怎么用:`slice` 不改原数组、`splice` 改;`sort` 默认按字符串,数字排序必须传比较函数;`forEach` 无返回值且不能 `break`,需中断时用 `for…of` 或 `some`。 常见误区:`replace` 不加全局标志只替换第一处;`map` 里只做副作用不 return(得到 undefined 数组)。 **15. 闭包与内存管理** 是什么:闭包是函数记住并访问其词法作用域,即使外层函数已返回;内存分栈(原始值、执行上下文)与堆(对象),回收以标记清除为主。 为什么重要:闭包是私有变量、计数器、防抖节流、模块模式的基础,也是泄漏高发区。 怎么用:只在需要"记住状态"时使用;不再需要时引用置 `null`、清除定时器与监听、解除 DOM 引用。 常见误区:以为闭包必然泄漏(被长期持有才泄漏);以为"返回函数"才叫闭包;循环里用 `var` 造出共享变量的"假闭包"。 ## 三、关键概念速查表 | 概念 | 一句话解释 | 用在哪儿 | |---|---|---| | ECMAScript | 语言规范本身,不含页面 API | 判断某个 API 是否"原生" | | DOM / BOM | 文档操作接口 / 浏览器窗口接口 | 页面交互、地址与历史 | | 严格模式 | 更严格语义的开关 | 新项目、模块、class | | 暂时性死区 | `let/const` 声明前不可访问 | 解释 "Cannot access before initialization" | | 提升 | 声明被提到作用域顶部 | 读老代码、排查 undefined | | 假值 | 7 个转为 false 的值 | 条件判断、默认值 | | 短路求值 | 逻辑运算符提前返回操作数 | 默认值、条件调用 | | 词法作用域 | 作用域由书写位置决定 | 闭包、模块化 | | 作用域链 | 变量由内向外逐层查找 | 调试变量来源 | | this | 调用时确定的上下文引用 | 方法、回调、事件处理 | | 原型链 | 属性查找的委托链 | 继承、方法复用 | | 闭包 | 函数 + 定义时的作用域 | 私有状态、防抖节流 | | IIFE | 定义后立即执行的函数 | 隔离作用域、避免污染 | | 回调函数 | 作为参数传入、稍后执行的函数 | 异步、事件、数组方法 | | 递归 | 函数调用自身且有终止条件 | 树形结构、深拷贝 | | 标记清除 | 从根可达性判断存活对象 | 理解内存泄漏 | ## 四、可复用的方法/框架 **变量声明决策树**:要改吗?不改用 `const`,要改用 `let`,只有维护老代码或需要函数级提升才用 `var`。写完回看:有没有在块外使用块内变量? **类型判断四步**:先 `=== null`;再 `Array.isArray`;再 `typeof`;最后 `Object.prototype.toString.call` 兜底。任何情况下都不靠 `typeof` 判数组或 null。 **this 判定四步**:是箭头函数(是→看外层)→ 是否 `new` 调用 → 是否 `call/apply/bind` → 是否 `obj.fn()` 形式 → 都不是则为默认绑定。函数被"摘下来"单独传递时,默认按丢失 this 处理。 **读代码的提升推演法**:先扫描 `var` 与函数声明并画到作用域顶部,标注 `undefined`;再执行赋值;最后标出 `let/const` 的死区范围。三步做完,"输出什么"的题基本可静态推出。 **内存泄漏排查清单**:全局变量是否意外创建 → 定时器/监听是否成对清除 → 闭包是否持有大对象 → DOM 移除后是否仍被 JS 引用 → 缓存是否有上限。 **闭包三问**:这个函数在定义时能看到哪些变量?它被谁持有、持有多久?它让哪些本该释放的对象继续活着?三问答完,既能判断闭包是否必要,也能判断是否构成泄漏。 **异步代码的三层读法**:先看同步部分执行顺序,再看回调/Promise 被排到哪个队列,最后看错误在哪一层被吞掉。绝大多数"顺序不对"的问题出在第二层,而不是逻辑写错。 ## 五、我的阅读轨迹 | 项目 | 数据 | |---|---| | 进度 | 100% | | 累计阅读 | 5 小时 14 分钟 | | 开始阅读 | 2024-04-19 | | 最近阅读 | 2024-05-08 | | 读完时间 | 2024-05-08 | 19 天读完 8 章,平均每天约 16 分钟,属于"通读一遍"而非"精读消化"的节奏。全书已读完,但按原理密度看,第8章(预解析、this、闭包、内存)与第7章(原型链)值得二次精读——这两处是面试与实战高频区,也是第一遍最容易"看懂但写不出"的地方。 复习建议: 1. 第一轮(现在):只重读第8章,配合手写输出题自测,不求快。 2. 第二轮(两周后):重读第3、4章的类型转换与比较,把 `==` 转换表亲手推一遍。 3. 第三轮(一个月后):以第7章原型链为线索,把内置对象方法按"是否改变原对象"重新归类。 4. 长期:把"核心知识点"当检查表,能不看资料讲清每条即为掌握。 5. 补读:目录外的 BOM/DOM/AJAX/异步部分,按简介承诺补齐(章节位置待核对)。 ## 六、行动清单 1. 手写 10 道预解析输出题,先推演再运行验证。 2. 用 `var` 与 `let` 各写一遍循环 + 定时器,对比输出并写下原因。 3. 整理一张 `==` 隐式转换对照表,覆盖 `null/undefined/0/''/false/[]`。 4. 实现闭包计数器与防抖函数,标注闭包持有了哪些变量。 5. 用 `Object.create` 手写原型继承,再与 `class` 写法对照。 6. 把项目里一处 `||` 默认值改成 `??`,验证边界行为。 7. 复述 this 的五种绑定与优先级,卡壳处回读第8章。 8. 补读 BOM/DOM/AJAX/异步章节(位置待核对),补齐知识面。 ## 七、延伸阅读 1. **《JavaScript 高级程序设计》**——同为系统教程,覆盖面更广、规范细节更全。建议本书之后读,用已建立的主线去消化细节;顺序不宜颠倒,否则易被篇幅劝退。 2. **《你不知道的 JavaScript》(上/中/下)**——专攻作用域、this、原型、异步等反直觉部分。适合本书第8章之后立即跟进,作为加深而非替代。 3. **《JavaScript 语言精粹》**——篇幅短、观点强,讲如何避开语言糟粕。适合第三本,在认知完整后做"减法",形成自己的编码风格。