ES6是下一代JavaScript语言标准的统称,每年6月发布一次修订版,迄今为止已经发布了3个版本,分别是ES2015、ES2016、ES2017。本书根据ES2017标准,详尽介绍了所有新增的语法,对基本概念、设计目的和用法进行了清晰的讲解,给出了大量简单易懂的示例。本书为中级难度,适合那些已经对JavaScript语言有一定了解的读者,可以作为学习这门语言*进展的工具书,也可以作为参考手册供大家随时查阅新语法。第3版增加了超过30%的内容,完全覆盖了ES2017标准,相比第2版介绍了更多的语法点,还调整了原有章节的文字表达,充实了示例,论述更准确,更易懂易学。
横跨ES2015/2016/2017新标,抢占JavaScript制高点
由千万级名博、布道引领无数前端入行的阮一峰执笔
来自BAT一线实践,精彩案例透彻解读新标|保留语法
新标首著,凝结多年研究心得,剖析ES理解应用难题
第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日,写于杭州
第1版前言
2012年年底,我开始动手做一个开源项目《JavaScript标准参考教程》(github.com/ruanyf/
jstutorial)。原来的设想是将自己的学习笔记整理成一本书,哪里料到,这个项目不断膨胀,最后变成了ECMAScript 5及其外围API的全面解读和参考手册,写了一年多还没写完。
那个项目的最后一章就是ECMAScript 6的语法简介。那一章也是越写越长,最后我不得不决定,把它独立出来,作为一个新项目,也就是您现在看到的这本书。
JavaScript已经是互联网开发的第一大语言,而且正在变成一种全领域的语言。著名程序员Jeff Atwood甚至提出了一条Atwood定律:所有可以用JavaScript编写的程序,最终都会出现JavaScript的版本。(Any application that can be written in JavaScript will eventually be
written in JavaScript.)
ECMAScript正是JavaScript的国际标准,这就决定了该标准的重要性。而ECMAScript 6是ECMAScript历史上最大的一次版本升级,在语言的各个方面都有极大的变化,即使是熟练的JavaScript程序员,也需要重新学习。由于ES6的设计目标是企业级开发和大型项目,所以可以预料,除了互联网开发者,将来还会有大量应用程序开发者(甚至操作系统开发者)成为ES6的学习者。
我写作这本书的目标,就是想为上面这些学习者提供一本篇幅较短、简明易懂、符合中文表达习惯的ES6教程。它由浅入深、循序渐进,既有重要概念的讲解,又有API接口的罗列,便于日后当作参考手册查阅,还提供大量示例代码,让读者不仅一看就懂,还能举一反三,直接复制用于实际项目之中。
需要声明的是,为了突出重点,本书只涉及ES6与ES5的不同之处,不对JavaScript已有的语法进行全面讲解,毕竟市面上这样的教程已经有很多了。因此,本书不是JavaScript入门教材,不适合初学者。阅读本书之前,需要对JavaScript的基本语法有所了解。
我本人也是一个ES6的学习者,不敢说自己有多高的水平,只是较早地接触了这个主题,持续地读了许多资料,追踪标准的进展,做了详细的笔记而已。虽然我尽了最大努力,并且原稿在GitHub上公开后已经得到了大量的勘误,但是本书的不尽如人意之处恐怕还有不少。
欢迎大家访问本书的项目主页(github.com/ruanyf/es6tutorial),提出意见,提交pull request。这些都会包括在本书的下一个版本中。
阮一峰
2014年6月4日,写于上海
阮一峰,资深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 配置文件.babelrc5
1.6.2 命令行转码babel-cli6
1.6.3 babel-node7
1.6.4 babel-register8
1.6.5 babel-core8
1.6.6 babel-polyfill9
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.EPSILON88
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 绑定this123
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.entries171
9.10 对象的扩展运算符173
9.11 Object.getOwnPropertyDescriptors()177
9.12 Null传导运算符181
第10章 Symbol183
10.1 概述183
10.2 作为属性名的Symbol185
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.hasInstance194
10.7.2 Symbol.isConcatSpreadable195
10.7.3 Symbol.species196
10.7.4 Symbol.match197
10.7.5 Symbol.replace197
10.7.6 Symbol.search198
10.7.7 Symbol.split198
10.7.8 Symbol.iterator199
10.7.9 Symbol.toPrimitive200
10.7.10 Symbol.toStringTag201
10.7.11 Symbol.unscopables202
第11章 Set和Map数据结构205
11.1 Set205
11.1.1 基本用法205
11.1.2 Set实例的属性和方法207
11.1.3 遍历操作208
11.2 WeakSet212
11.2.1 含义212
11.2.2 语法212
11.3 Map214
11.3.1 含义和基本用法214
11.3.2 实例的属性和操作方法218
11.3.3 遍历方法220
11.3.4 与其他数据结构的互相转换222
11.4 WeakMap225
11.4.1 含义225
11.4.2 WeakMap的语法227
11.4.3 WeakMap示例228
11.4.4 WeakMap的用途229
第12章 Proxy233
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章 Reflect259
13.1 概述259
13.2 静态方法261
13.2.1 Reflect.get(target, name, receiver)262
13.2.2 Reflect.set(target, name, value, receiver)263
13.2.3 Reflect.has(obj, name)264
13.2.4 Reflect.deleteProperty(obj, name)265
13.2.5 Reflect.construct(target, args)265
13.2.6 Reflect.getPrototypeOf(obj)265
13.2.7 Reflect.setPrototypeOf(obj, newProto)266
13.2.8 Reflect.apply(func, thisArg, args)267
13.2.9 Reflect.defineProperty(target, propertyKey, attributes)267
13.2.10 Reflect.getOwnPropertyDescriptor (target, propertyKey)268
13.2.11 Reflect.isExtensible (target)268
13.2.12 Reflect.preventExtensions(target)269
13.2.13 Reflect.ownKeys (target)269
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.9.1 done()291
14.9.2 finally()292
14.10 应用292
14.10.1 加载图片292
14.10.2 Generator函数与Promise的结合293
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
15.7.1 数组310
15.7.2 Set和Map结构311
15.7.3 计算生成的数据结构312
15.7.4 类似数组的对象313
15.7.5 对象314
15.7.6 与其他遍历语法的比较315
第16章 Generator函数的语法317
16.1 简介317
16.1.1 基本概念317
16.1.2 yield表达式319
16.1.3 与Iterator接口的关系322
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 作为对象属1