编辑推荐
适读人群 :JavaScript领域研究人员,前端开发人员 √ 横跨ES2015/2016/2017新标,抢占JavaScript制高点
√ 由千万级名博、布道引领无数前端入行的阮一峰执笔
√ 来自BAT一线实践,精彩案例透彻解读新标|保留语法
√ 新标首著,凝结多年研究心得,剖析ES理解应用难题
内容简介
ES6是下一代JavaScript语言标准的统称,每年6月发布一次修订版,迄今为止已经发布了3个版本,分别是ES2015、ES2016、ES2017。《ES6标准入门(第3版)》根据ES2017标准,详尽介绍了所有新增的语法,对基本概念、设计目的和用法进行了清晰的讲解,给出了大量简单易懂的示例。《ES6标准入门(第3版)》为中级难度,适合那些已经对JavaScript语言有一定了解的读者,可以作为学习这门语言全新进展的工具书,也可以作为参考手册供大家随时查阅新语法。 第3版增加了超过30%的内容,完全覆盖了ES2017标准,相比第2版介绍了更多的语法点,还调整了原有章节的文字表达,充实了示例,论述更准确,更易懂易学。
作者简介
阮一峰,资深JavaScript 语言专家,知名技术博客作者,专注于网站开发技术十余年。畅销书《黑客与画家》《软件随想录》的译者,现就职于蚂蚁金服集团。
目录
第1章 ECMAScript 6简介 1
1.1 ECMAScript和JavaScript的关系 1
1.2 ES6与ECMAScript 2015的关系 1
1.3 语法提案的批准流程 2
1.4 ECMAScript的历史 3
1.5 部署进度 4
1.6 Babel 转码器 4
1.6.1 配置文件.babelrc 5
1.6.2 命令行转码babel-cli 6
1.6.3 babel-node 7
1.6.4 babel-register 8
1.6.5 babel-core 8
1.6.6 babel-polyfill 9
1.6.7 浏览器环境 10
1.6.8 在线转换 10
1.6.9 与其他工具的配合 11
1.7 Traceur转码器 11
1.7.1 直接插入网页 12
1.7.2 在线转换 13
1.7.3 命令行转换 14
1.7.4 Node环境的用法 15
第2章 let和const命令 17
2.1 let 命令 17
2.1.1 基本用法 17
2.1.2 不存在变量提升 19
2.1.3 暂时性死区 19
2.1.4 不允许重复声明 21
2.2 块级作用域 22
2.2.1 为什么需要块级作用域 22
2.2.2 ES6的块级作用域 23
2.2.3 块级作用域与函数声明 24
2.2.4 do表达式 27
2.3 const命令 28
2.3.1 基本用法 28
2.3.2 本质 29
2.3.3 ES6声明变量的6种方法 30
2.4 顶层对象的属性 30
2.5 global对象 31
第3章 变量的解构赋值 33
3.1 数组的解构赋值 33
3.1.1 基本用法 33
3.1.2 默认值 35
3.2 对象的解构赋值 37
3.3 字符串的解构赋值 41
3.4 数值和布尔值的解构赋值 41
3.5 函数参数的解构赋值 42
3.6 圆括号问题 43
3.6.1 不能使用圆括号的情况 43
3.6.2 可以使用圆括号的情况 44
3.7 用途 44
第4章 字符串的扩展 49
4.1 字符的Unicode表示法 49
4.2 codePointAt() 50
4.3 String.fromCodePoint() 52
4.4 字符串的遍历器接口 52
4.5 at() 53
4.6 normalize() 53
4.7 includes()、startsWith()、endsWith() 54
4.8 repeat() 55
4.9 padStart()、padEnd() 56
4.10 模板字符串 57
4.11 实例:模板编译 60
4.12 标签模板 62
4.13 String.raw() 67
4.14 模板字符串的限制 68
第5章 正则的扩展 71
5.1 RegExp构造函数 71
5.2 字符串的正则方法 72
5.3 u修饰符 72
5.4 y修饰符 74
5.5 sticky属性 77
5.6 flags属性 77
5.7 s修饰符:dotAll模式 78
5.8 后行断言 79
5.9 Unicode属性类 80
5.10 具名组匹配 81
5.10.1 简介 81
5.10.2 解构赋值和替换 82
5.10.3 引用 83
第6章 数值的扩展 85
6.1 二进制和八进制表示法 85
6.2 Number.isFinite()、Number.isNaN() 86
6.3 Number.parseInt()、Number.parseFloat() 87
6.4 Number.isInteger() 88
6.5 Number.EPSILON 88
6.6 安全整数和Number.isSafeInteger() 89
6.7 Math对象的扩展 92
6.7.1 Math.trunc() 92
6.7.2 Math.sign() 92
6.7.3 Math.cbrt() 93
6.7.4 Math.clz32() 94
6.7.5 Math.imul() 95
6.7.6 Math.fround() 95
6.7.7 Math.hypot() 96
6.7.8 对数方法 96
6.7.9 双曲函数方法 98
6.8 Math.signbit() 98
6.9 指数运算符 99
6.10 Integer数据类型 99
6.10.1 简介 99
6.10.2 运算 100
第7章 函数的扩展 103
7.1 函数参数的默认值 103
7.1.1 基本用法 103
7.1.2 与解构赋值默认值结合使用 105
7.1.3 参数默认值的位置 107
7.1.4 函数的length属性 108
7.1.5 作用域 108
7.1.6 应用 111
7.2 rest参数 112
7.3 严格模式 113
7.4 name属性 115
7.5 箭头函数 116
7.5.1 基本用法 116
7.5.2 注意事项 118
7.5.3 嵌套的箭头函数 121
7.6 绑定this 123
7.7 尾调用优化 124
7.7.1 什么是尾调用 124
7.7.2 尾调用优化 125
7.7.3 尾递归 126
7.7.4 递归函数的改写 128
7.7.5 严格模式 129
7.7.6 尾递归优化的实现 129
7.8 函数参数的尾逗号 132
第8章 数组的扩展 133
8.1 扩展运算符 133
8.1.1 含义 133
8.1.2 替代数组的apply方法 134
8.1.3 扩展运算符的应用 136
8.2 Array.from() 139
8.3 Array.of() 142
8.4 数组实例的copyWithin() 143
8.5 数组实例的find()和findIndex() 144
8.6 数组实例的fill() 145
8.7 数组实例的entries()、keys()和values() 145
8.8 数组实例的includes() 146
8.9 数组的空位 147
第9章 对象的扩展 151
9.1 属性的简洁表示法 151
9.2 属性名表达式 154
9.3 方法的name属性 156
9.4 Object.is() 157
9.5 Object.assign() 158
9.5.1 基本用法 158
9.5.2 注意点 160
9.5.3 常见用途 161
9.6 属性的可枚举性 163
9.7 属性的遍历 165
9.8 __proto__ 属性、Object.setPrototypeOf()、Object.getPrototypeOf() 166
9.8.1 __proto__ 属性 166
9.8.2 Object.setPrototypeOf() 167
9.8.3 Object.getPrototypeOf() 168
9.9 Object.keys()、Object.values()、Object.entries() 169
9.9.1 Object.keys() 169
9.9.2 Object.values() 170
9.9.3 Object.entries 171
9.10 对象的扩展运算符 173
9.11 Object.getOwnPropertyDescriptors() 177
9.12 Null传导运算符 181
第10章 Symbol 183
10.1 概述 183
10.2 作为属性名的Symbol 185
10.3 实例:消除魔术字符串 188
10.4 属性名的遍历 189
10.5 Symbol.for()、Symbol.keyFor() 191
10.6 实例:模块的Singleton模式 192
10.7 内置的Symbol值 194
10.7.1 Symbol.hasInstance 194
10.7.2 Symbol.isConcatSpreadable 195
10.7.3 Symbol.species 196
10.7.4 Symbol.match 197
10.7.5 Symbol.replace 197
10.7.6 Symbol.search 198
10.7.7 Symbol.split 198
10.7.8 Symbol.iterator 199
10.7.9 Symbol.toPrimitive 200
10.7.10 Symbol.toStringTag 201
10.7.11 Symbol.unscopables 202
第11章 Set和Map数据结构 205
11.1 Set 205
11.1.1 基本用法 205
11.1.2 Set实例的属性和方法 207
11.1.3 遍历操作 208
11.2 WeakSet 212
11.2.1 含义 212
11.2.2 语法 212
11.3 Map 214
11.3.1 含义和基本用法 214
11.3.2 实例的属性和操作方法 218
11.3.3 遍历方法 220
11.3.4 与其他数据结构的互相转换 222
11.4 WeakMap 225
11.4.1 含义 225
11.4.2 WeakMap的语法 227
11.4.3 WeakMap示例 228
11.4.4 WeakMap的用途 229
第12章 Proxy 233
12.1 概述 233
12.2 Proxy实例的方法 237
12.2.1 get() 237
12.2.2 set() 241
12.2.3 apply() 243
12.2.4 has() 244
12.2.5 construct() 246
12.2.6 deleteProperty() 247
12.2.7 defineProperty() 248
12.2.8 getOwnPropertyDescriptor() 248
12.2.9 getPrototypeOf() 249
12.2.10 isExtensible() 249
12.2.11 ownKeys() 250
12.2.12 preventExtensions() 254
12.2.13 setPrototypeOf() 255
12.3 Proxy.revocable() 255
12.4 this问题 256
12.5 实例:Web服务的客户端 258
第13章 Reflect 259
13.1 概述 259
13.2 静态方法 261
13.3 实例:使用Proxy实现观察者模式 270
第14章 Promise对象 273
14.1 Promise的含义 273
14.2 基本用法 274
14.3 Promise.prototype.then() 278
14.4 Promise.prototype.catch() 279
14.5 Promise.all() 285
14.6 Promise.race() 287
14.7 Promise.resolve() 288
14.8 Promise.reject() 290
14.9 两个有用的附加方法 291
14.10 应用 292
14.11 Promise.try() 294
第15章 Iterator和for...of循环 297
15.1 Iterator(遍历器)的概念 297
15.2 默认Iterator接口 300
15.3 调用Iterator接口的场合 305
15.4 字符串的Iterator接口 307
15.5 Iterator接口与Generator函数 308
15.6 遍历器对象的return()、throw() 309
15.7 for...of循环 310
第16章 Generator函数的语法 317
16.1 简介 317
16.2 next方法的参数 323
16.3 for...of循环 325
16.4 Generator.prototype.throw() 328
16.5 Generator.prototype.return() 334
16.6 yield*表达式 335
16.7 作为对象属性的Generator函数 342
16.8 Generator函数this 342
16.9 含义 345
16.10 应用 347
第17章 Generator函数的异步应用 355
17.1 传统方法 355
17.2 基本概念 355
17.3 Generator函数 357
17.4 Thunk函数 361
17.5 co模块 368
17.6 实例:处理 Stream 373
第18章 async函数 375
18.1 含义 375
18.2 用法 377
18.3 语法 379
18.4 async函数的实现原理 386
18.5 其他异步处理方法的比较 387
18.6 实例:按顺序完成异步操作 388
18.7 异步遍历器 390
第19章 Class的基本语法 399
19.1 简介 399
19.2 严格模式 403
19.3 constructor方法 403
19.4 类的实例对象 404
19.5 Class表达式 406
19.6 不存在变量提升 407
19.7 私有方法 408
19.8 私有属性 409
19.9 this的指向 410
19.10 name属性 412
19.11 Class的取值函数(getter)和存值函数(setter) 412
19.12 Class的Generator方法 413
19.13 Class的静态方法 414
19.14 Class的静态属性和实例属性 415
19.15 new.target属性 418
第20章 Class的继承 421
20.1 简介 421
20.2 Object.getPrototypeOf() 423
20.3 super关键字 423
20.4 类的prototype属性和 __proto__ 属性 429
20.4.1 extends的继承目标 430
20.4.2 实例的 __proto__ 属性 432
20.5 原生构造函数的继承 432
20.6 Mixin模式的实现 436
第21章 修饰器 439
21.1 类的修饰 439
21.2 方法的修饰 442
21.3 为什么修饰器不能用于函数 444
21.4 core-decorators.js 446
21.5 使用修饰器实现自动发布事件 449
21.6 Mixin 450
21.7 Trait 453
21.8 Babel转码器的支持 456
第22章 Module的语法 457
22.1 概述 457
22.2 严格模式 458
22.3 export命令 459
22.4 import命令 462
22.5 模块的整体加载 464
22.6 export default命令 465
22.7 export与import的复合写法 468
22.8 模块的继承 469
22.9 跨模块常量 470
22.10 import() 471
22.10.1 简介 471
22.10.2 适用场合 472
22.10.3 注意点 473
第23章 Module的加载实现 475
23.1 浏览器加载 475
23.1.1 传统方法 475
23.1.2 加载规则 476
23.2 ES6模块与CommonJS模块的差异 477
23.3 Node加载 481
23.4 循环加载 485
23.5 ES6模块的转码 492
第24章 编程风格 495
24.1 块级作用域 495
24.2 字符串 497
24.3 解构赋值 497
24.4 对象 498
24.5 数组 500
24.6 函数 501
24.7 Map结构 503
24.8 Class 503
24.9 模块 504
24.10 ESLint的使用 506
第25章 读懂ECMAScript规格 509
25.1 概述 509
25.2 相等运算符 510
25.3 数组的空位 511
25.4 数组的map方法 513
第26章 ArrayBuffer 517
26.1 ArrayBuffer对象 518
26.2 TypedArray视图 521
26.3 复合视图 534
26.4 DataView视图 535
26.5 二进制数组的应用 537
26.6 SharedArrayBuffer 541
26.7 Atomics对象 543
前言/序言
第3版前言
4年前,当我开始写这本书的时候,ECMAScript 5.1版刚刚开始普及,最流行的框架还是jQuery。ES6看上去就像一个遥远的蓝图,无人知道何时会实现。
仅仅4年,ES6已经经历了ES2015、ES2016、ES2017这3个版本的迭代,各种实现的支持度已经超过90%,不仅可以实现网页的编写,还可以实现服务器脚本、手机App和桌面应用的编写。程序员们完全接受了这个标准,甚至大量使用尚未标准化的新语法。JavaScript语言就像一列高铁,以令人“眩晕”的速度向前冲刺。
互联网行业的蓬勃兴旺造就了ES6的成功,也使得这本教程不断更新,越写越厚。第2版问世18个月之后,不得不推出第3版。
第3版新增了超过30%的内容,完全覆盖了ES2017标准(第2版只做到覆盖 ES2015标准),并且对所有章节都进行了修订,文字表达更准确易懂,示例更丰富。对读者来说,这个版本更容易学习,更有参考价值。
这4年来,我对ES6的理解和所有的学习笔记,都浓缩在这本教程里面。那些我自己感到最困难的地方,书中都做出了详细讲解,给出了细致的示例,我相信这也是其他国内学习者所需要的。
这本教程当然也包含了些许局限,以及细致检查之后仍然疏漏的各种错误。一旦发现,我会第一时间更正。读者可以到官方仓库github.com/ruanyf/es6tutorial中查看勘误。
我在微博上曾经说过一段话,就把它放在这里作为结束吧。
“我水平其实不高,只是好奇心重,从没想到这么多人会关注。希望不要让大家失望,未来做一块垫脚石,为需要的朋友提供帮助,为技术的推广和发展做出力所能及的贡献。”
阮一峰
2017年8月1日,写于杭州
《JavaScript深入剖析》(修订版) 一本献给每一位 JavaScript 探索者,深度解读语言核心的旅程。 在飞速发展的 Web 技术浪潮中,JavaScript 扮演着无可替代的角色,从前端的交互到后端的服务,它无处不在,驱动着现代互联网的脉搏。然而,仅仅掌握 JavaScript 的基本语法和常用 API,或许能让我们构建出功能性的应用,但要真正理解其精髓,触及其运行的底层机制,以及写出更健壮、高效、易于维护的代码,则需要更深入的探索。 《JavaScript 深入剖析》(修订版)正是一次对 JavaScript 语言深层奥秘的系统性揭示。本书并非泛泛而谈,而是聚焦于 JavaScript 最核心、最底层的工作原理,力求为读者构建一个清晰、透彻的认知模型。我们相信,只有深入理解了事物运作的本质,才能在复杂的技术栈中游刃有余,做出更明智的技术决策,成为一名真正的 JavaScript 架构师。 本书内容概览: 第一部分:JavaScript 引擎与执行上下文——揭开代码运行的神秘面纱 JavaScript 引擎的运作原理: 我们将从 JavaScript 引擎(如 V8、SpiderMonkey)如何解析、编译和执行 JavaScript 代码入手。深入理解词法分析、语法分析、抽象语法树(AST)的生成过程,以及即时编译(JIT)是如何在性能与兼容性之间取得平衡的。 执行上下文栈与全局上下文: 详细阐述执行上下文的概念,包括全局执行上下文的创建过程,以及它在整个 JavaScript 程序生命周期中的作用。 函数执行上下文与作用域链: 深入解析当函数被调用时,如何创建新的函数执行上下文,以及作用域链是如何形成和工作的。理解词法作用域(Lexical Scoping)与动态作用域(Dynamic Scoping)的区别,以及闭包(Closure)的形成机制及其在内存管理上的影响。 `this` 的指向机制: 毫无疑问,`this` 是 JavaScript 中最令人困惑的概念之一。本书将系统地梳理 `this` 在不同调用场景下的指向规则,包括全局调用、对象方法调用、构造函数调用、箭头函数以及通过 `call`、`apply`、`bind` 进行显式绑定。通过大量的实例,彻底剖析 `this` 的行为模式。 变量提升(Hoisting)与函数声明提升: 深入解析 JavaScript 在代码执行前,对变量声明和函数声明进行的“提升”操作。理解 `var`、`let`、`const` 在变量提升方面的差异,以及它们对代码可读性和可维护性的影响。 单线程与事件循环(Event Loop): JavaScript 的单线程模型是理解其异步编程的关键。本书将详细讲解事件循环、宏任务(Macrotasks)与微任务(Microtasks)的概念,以及它们是如何协同工作,处理异步操作,避免阻塞主线程的。我们将通过图示和代码示例,直观展示事件循环的执行流程。 第二部分:内存管理与垃圾回收——理解资源的生命周期 内存模型:栈(Stack)与堆(Heap): 阐述 JavaScript 中内存的两种主要存储区域:栈内存(用于存储基本类型数据和函数调用信息)和堆内存(用于存储对象、数组等引用类型数据)。 值类型(Value Types)与引用类型(Reference Types): 区分值类型(如 `number`、`string`、`boolean`)和引用类型(如 `object`、`array`、`function`),理解它们在内存中的存储方式以及赋值操作的区别。 垃圾回收机制(Garbage Collection, GC): 讲解 JavaScript 引擎是如何自动进行内存管理的。重点介绍标记-清除(Mark-Sweep)和引用计数(Reference Counting)等主流的垃圾回收算法,分析它们的工作原理、优缺点以及可能遇到的内存泄漏场景。 内存泄漏的常见原因与避免: 深入探讨在 JavaScript 开发中容易导致内存泄漏的常见模式,例如未清除的定时器、未移除的事件监听器、闭包中的循环引用等。提供切实可行的检测和避免内存泄漏的策略。 第三部分:原型链与继承——构建对象关系的基石 原型(Prototype)与原型链(Prototype Chain): 彻底解析 JavaScript 的原型机制。理解每个对象都拥有一个内部的 `[[Prototype]]` 属性,指向其原型对象,以及对象在访问属性时,如何沿着原型链向上查找。 构造函数(Constructor)与 `new` 操作符: 详细解释构造函数的作用,以及 `new` 操作符在创建对象时所执行的一系列步骤:创建新对象、绑定原型、设置构造函数、返回新对象。 原型链继承(Prototype Chain Inheritance): 演示如何利用原型链实现继承,这是 JavaScript 中最经典的继承模式。分析其优缺点。 `Object.create()` 与其他继承方式: 介绍 `Object.create()` 方法如何直接创建一个新对象,并将其与指定的原型对象关联,以及这种方式在实现继承上的灵活性。 ES6 Class 的本质: 剖析 ES6 `class` 语法糖的背后,其实质仍然是基于原型的继承。理解 `class` 如何简化了原型继承的编写,但其底层机制并未改变。 第四部分:异步编程与并发模型——驾驭非阻塞的世界 回调函数(Callback Functions): 回顾回调函数在早期 JavaScript 异步编程中的作用,并分析其可能带来的“回调地狱”(Callback Hell)问题。 Promise: 深入讲解 Promise 的状态(pending, fulfilled, rejected)和链式调用。理解 `.then()`、`.catch()`、`.finally()` 的用法,以及如何利用 Promise 优化异步代码的结构和可读性。 Generator 函数: 探索 Generator 函数的 `yield` 关键字,如何实现异步操作的可暂停与恢复。理解 Generator 在控制流管理上的强大能力。 Async/Await: 重点讲解 `async` 和 `await` 关键字如何让异步代码的书写方式更接近同步代码。深入理解它们与 Promise 的结合,以及如何显著提升异步代码的可维护性。 Web Workers: 介绍 Web Workers 如何在浏览器中实现真正的多线程,允许在后台运行脚本,避免阻塞主线程,从而提高应用程序的响应速度。 第五部分:模块化与模块系统——组织大型项目的关键 CommonJS 模块规范: 讲解 Node.js 中广泛使用的 CommonJS 模块规范,包括 `require` 和 `module.exports` 的工作原理。 AMD 模块规范: 介绍 AMD(Asynchronous Module Definition)规范,以及它在浏览器环境下异步加载模块的优势。 ES Modules (ESM): 详细阐述 ECMAScript 官方提出的模块化标准。深入理解 `import` 和 `export` 的语法、静态分析的优势,以及 ESM 在浏览器和 Node.js 中的应用。 模块打包工具(如 Webpack, Rollup)的原理浅析: 简要介绍主流模块打包工具的核心功能,如代码分割、依赖解析、Tree Shaking 等,帮助读者理解它们是如何将模块化的代码最终打包成高效可用的资源的。 本书的独特价值: 深度与广度并存: 本书不仅深入剖析了 JavaScript 的底层机制,同时也覆盖了从基础到高级的各个重要方面,为读者构建了一个全面的知识体系。 理论与实践相结合: 每一章节都配以清晰的图示、精炼的代码示例和详尽的解释,帮助读者在理解理论的同时,能够将其应用于实际开发中。 面向开发者,解决痛点: 本书旨在解决开发者在实际工作中遇到的许多共性问题,如 `this` 指向不清、内存泄漏、异步流程混乱等,提供根本性的解决方案。 循序渐进,由浅入深: 采用逻辑严谨的章节安排,从最基础的引擎原理开始,逐步深入到更复杂的概念,确保不同经验水平的读者都能从中受益。 助您成为更优秀的 JavaScript 工程师: 通过对 JavaScript 核心机制的深刻理解,您将能够写出更优化的代码,更准确地进行性能调优,更有效地排查疑难杂症,最终成为一名在 JavaScript 领域具有深厚功底的工程师。 无论您是刚踏入 JavaScript 世界的新手,希望打下坚实的基础;还是身经百战的资深开发者,渴望突破瓶颈,探寻语言的本质,《JavaScript 深入剖析》(修订版)都将是您不可或缺的学习伴侣。 翻开本书,开启您的 JavaScript 深度探索之旅!