书籍详情
深入理解现代JavaScript
作者:[美]T. J. 克罗德(T. J. Crowder)著 赵永、卢贤泼 译
出版社:清华大学出版社
出版时间:2022-04-01
ISBN:9787302602118
定价:¥128.00
购买这本书可以去
内容简介
本书主要内容 l 涵盖ES2015~ES2020中JavaScript的所有新特性以及下一版的预览。 l 探索**的语法:空值合并、可选链、let和const、类语法、私有方法、私有字段、new.target、数字分隔符、BigInt、解构、默认参数、箭头函数、异步函数、await、生成器函数、…(rest和spread操作符)、模板字面量、二进制和八进制字面量、**(求幂运算符)、计算属性/方法名、for-of、for-await-of、属性的简写语法等。 l 详细介绍新特性和模式:模块、Promise、迭代、生成器、Symbol、代理、反射、类型化数组、Atomics、共享内存、WeakMap、WeakSet等。 l 揭示常见的陷阱并阐述如何避免它们。 l 展示如何跟进和参与JavaScript的改进流程。 l 介绍如何在新特性获得广泛支持之前使用它们。
作者简介
T. J. Crowder是一位拥有30年经验的软件工程师。在他的整个职业生涯中,他至少有一半时间是在使用JavaScript从事开发工作。他经营着软件承包和产品公司Farsight Software。他经常在Stack Overflow上为人们提供帮助,他是十大贡献者之一和JavaScript标签的贡献者。当他不工作或写作时,他总是与他美丽的、支持他的妻子和出色的儿子共度美好时光。
目录
第1章 ES2015~ES2020及后续版本的
新特性 1
1.1 名称、定义和术语 2
1.1.1 Ecma?ECMAScript?TC39? 2
1.1.2 ES6?ES7?ES2015?ES2020? 2
1.1.3 JavaScript“引擎”、浏览器及其他 3
1.2 什么是“新特性” 3
1.3 新特性的推动流程 5
1.3.1 谁负责 5
1.3.2 流程 5
1.3.3 参与 6
1.3.4 跟上新特性的步伐 7
1.4 旧环境中使用新特性 8
1.5 本章小结 12
第2章 块级作用域声明:let和const 13
2.1 let和const的介绍 13
2.2 真正的块级作用域 14
2.3 重复声明将抛出错误 15
2.4 提升和暂时性死区 15
2.5 一种新的全局变量 17
2.6 const:JavaScript的常量 19
2.6.1 const基础 19
2.6.2 常量引用的对象仍然是可变的 20
2.7 循环中的块级作用域 21
2.7.1 “循环中的闭包”问题 21
2.7.2 绑定:变量、常量以及其他
标识符的工作方式 23
2.7.3 while和do-while循环 27
2.7.4 性能影响 28
2.7.5 循环块中的const 29
2.7.6 for-in循环中的const 29
2.8 旧习换新 30
2.8.1 用const或let替代var 30
2.8.2 缩小变量的作用域 30
2.8.3 用块级作用域替代匿名函数 30
第3章 函数的新特性 33
3.1 箭头函数和this、super等词法 34
3.1.1 箭头函数语法 34
3.1.2 箭头函数和this词法 37
3.1.3 箭头函数不能被用作构造函数 38
3.2 默认参数值 38
3.2.1 默认值是表达式 39
3.2.2 默认值在自己的作用域中被计算 40
3.2.3 默认值不会增加函数的arity 42
3.3 “rest”参数 42
3.4 参数列表和函数调用中的
尾后逗号 44
3.5 函数的name属性 45
3.6 在语句块中声明函数 46
3.6.1 在语句块中声明函数:标准语义 48
3.6.2 在语句块中声明函数:
传统Web语义 49
3.7 旧习换新 51
3.7.1 使用箭头函数替代各种访问this
值的变通方式 51
3.7.2 在不使用this或arguments时,
回调函数使用箭头函数 52
3.7.3 考虑在更多地方使用箭头函数 52
3.7.4 当调用者需要控制this的值时,
不要使用箭头函数 53
3.7.5 使用参数默认值,而不是
代码实现 53
3.7.6 使用“rest”参数替代arguments
关键字 53
3.7.7 如有必要,考虑使用尾后逗号 53
第4章 类 55
4.1 类的概念 55
4.2 介绍新的类语法 56
4.2.1 添加构造函数 57
4.2.2 添加实例属性 59
4.2.3 添加原型方法 59
4.2.4 添加静态方法 61
4.3 添加访问器属性 61
4.4 对比新语法和旧语法 64
4.5 创建子类 66
4.6 关键字super 69
4.6.1 编写子类构造函数 69
4.6.2 继承和访问超类原型的属性和
方法 70
4.6.3 继承静态方法 73
4.6.4 静态方法中的super 75
4.6.5 返回新实例的方法 75
4.6.6 内置对象的子类 79
4.6.7 super的使用 81
4.7 移除Object.prototype 83
4.8 new.target 84
4.9 类声明与类表达式 87
4.9.1 类声明 87
4.9.2 类表达式 88
4.10 更多内容 89
4.11 旧习换新 89
第5章 对象的新特性 91
5.1 可计算属性名 91
5.2 属性的简写语法 92
5.3 获取和设置对象原型 93
5.3.1 Object.setPrototypeOf 93
5.3.2 浏览器环境中的__proto__属性 94
5.3.3 浏览器环境中的__proto__字面量
属性名 94
5.4 对象方法的简写语法,以及类
之外的super 95
5.5 Symbol 97
5.5.1 定义Symbol的原因 97
5.5.2 创建和使用Symbol 99
5.5.3 Symbol并不用于私有属性 99
5.5.4 全局Symbol 100
5.5.5 内置的Symbol值 103
5.6 对象的新增方法 104
5.6.1 Object.assign 104
5.6.2 Object.is 105
5.6.3 Object.values 105
5.6.4 Object.entries 106
5.6.5 Object.fromEntries 106
5.6.6 Object.getOwnPropertySymbols 106
5.6.7 Object.getOwnPropertyDescriptors 106
5.7 Symbol.toPrimitive 107
5.8 属性顺序 109
5.9 属性扩展语法 110
5.10 旧习换新 111
5.10.1 创建对象时对动态变量使用可
计算属性名 111
5.10.2 从同名变量初始化对象时,
使用简写语法 111
5.10.3 使用Object.assign替代自定义的
扩展方法或者显式复制所有
属性 112
5.10.4 基于已有对象创建新对象时,
使用属性扩展语法 112
5.10.5 使用Symbol避免属性名冲突 112
5.10.6 使用Object.getPrototypeOf/
setPrototypeOf替代__proto__ 112
5.10.7 使用对象方法的简写语法来
定义对象中的方法 112
第6章 可迭代对象、迭代器、for-of循环、
可迭代对象的展开语法和
生成器 115
6.1 迭代器、可迭代对象、for-of循环,
以及可迭代对象的展开语法 115
6.1.1 迭代器和可迭代对象 115
6.1.2 for-of循环:隐式地使用迭代器 116
6.1.3 显式地使用迭代器 117
6.1.4 提前停止迭代 118
6.1.5 迭代器的原型对象 119
6.1.6 使对象可迭代 121
6.1.7 使迭代器可迭代 124
6.1.8 可迭代对象的展开语法 126
6.1.9 迭代器、for-of循环和DOM 127
6.2 生成器函数 129
6.2.1 仅生成值的基本生成器函数 129
6.2.2 使用生成器函数创建迭代器 130
6.2.3 生成器函数作为方法 131
6.2.4 直接使用生成器 132
6.2.5 用生成器消费值 132
6.2.6 在生成器函数中使用return 136
6.2.7 yield运算符的优先级 136
6.2.8 return和throw方法:终止
生成器 137
6.2.9 生成生成器或者可迭代对象:
yield* 139
6.3 旧习换新 143
6.3.1 使用消费可迭代对象的结构 143
6.3.2 使用DOM集合的可迭代特性 144
6.3.3 使用可迭代对象和迭代器接口 144
6.3.4 在过去用Function.prototype.apply
的大部分场景中使用可迭代对象
的展开语法 144
6.3.5 使用生成器 144
第7章 解构 145
7.1 概览 145
7.2 基础的对象解构 145
7.3 基础的数组(和可迭代对象)的
解构 148
7.4 解构默认值 150
7.5 解构匹配模式中的“rest”语法 151
7.6 使用不同的名称 152
7.7 可计算属性名 153
7.8 嵌套解构 153
7.9 参数解构 154
7.10 循环中的解构 157
7.11 旧习换新 157
7.11.1 仅从对象获取某些属性时
使用解构 158
7.11.2 对可选项对象使用解构 158
第8章 Promise 159
8.1 为什么要使用Promise 159
8.2 Promise基础 160
8.2.1 概览 160
8.2.2 示例 161
8.2.3 Promise和thenable对象 163
8.3 使用已存在的Promise 163
8.3.1 then方法 163
8.3.2 链式Promise 164
8.3.3 对比Promise链与回调函数 168
8.3.4 catch方法 168
8.3.5 finally方法 170
8.3.6 在then、catch和finally处理程序
中抛出异常 173
8.3.7 带有两个参数的then方法 175
8.4 为已敲定状态的Promise添加
处理程序 176
8.5 创建Promise 177
8.5.1 Promise构造函数 178
8.5.2 Promise.resolve 180
8.5.3 Promise.reject 181
8.6 其他Promise工具方法 182
8.6.1 Promise.all 182
8.6.2 Promise.race 183
8.6.3 Promise.allSettled 184
8.6.4 Promise.any 184
8.7 Promise的模式 185
8.7.1 处理错误或返回Promise 185
8.7.2 串行Promise 185
8.7.3 并行Promise 187
8.8 Promise的反模式 188
8.8.1 不必要的new Promise(/*…*/) 188
8.8.2 未处理的错误(或不正确的
处理方式) 188
8.8.3 在转换回调函数API时隐藏了
错误 188
8.8.4 隐式地将已拒绝状态转换为已
成功状态 189
8.8.5 试图在链式调用外使用结果 190
8.8.6 使用无用的处理程序 190
8.8.7 错误地处理链式调用分支 191
8.9 Promise的子类 192
8.10 旧习换新 193
第9章 异步函数、迭代器和生成器 195
9.1 async函数 195
9.1.1 async函数创建Promise对象 197
9.1.2 await接收Promise 198
9.1.3 异步是使用await的常规思维
方式 199
9.1.4 拒绝即异常,异常即拒绝;成功值
就是结果,返回值就是决议 200
9.1.5 async函数中的并行操作 202
9.1.6 不必使用return await 203
9.1.7 陷阱:在意想不到的地方使用
async函数 204
9.2 异步迭代器、可迭代对象和
生成器 205
9.2.1 异步迭代器 205
9.2.2 异步生成器 208
9.2.3 for-await-of 209
9.3 旧习换新 210
第10章 模板字面量、标签函数和新的
字符串特性 211
10.1 模板字面量 211
10.1.1 基本功能(不带标签的模板
字面量) 212
10.1.2 模板标签函数(带标签的模板
字面量) 213
10.1.3 String.raw 218
10.1.4 模板字面量的复用 219
10.1.5 模板字面量和自动分号插入 219
10.2 改进的Unicode支持 219
10.2.1 Unicode以及JavaScript字符串的
含义 219
10.2.2 码点转义序列 221
10.2.3 String.fromCodePoint 221
10.2.4 String.prototype.codePointAt 221
10.2.5 String.prototype.normalize 222
10.3 迭代 223
10.4 新的字符串方法 224
10.4.1 String.prototype.repeat 224
10.4.2 String.prototype.startsWith和
endsWith 224
10.4.3 String.prototype.includes 225
10.4.4 String.prototype.padStart和
padEnd 225
10.4.5 String.prototype.trimStart和
trimEnd 226
10.5 match、split、search和replace
方法的更新 226
10.6 旧习换新 228
10.6.1 使用模板字面量替代字符串
连接(在适当的情况下) 228
10.6.2 对DSL使用标签函数和模板
字面量,而不是自动占位符
机制 228
10.6.3 使用字符串迭代 228
第11章 新数组特性、类型化数组 229
11.1 新的数组方法 229
11.1.1 Array.of 229
11.1.2 Array.from 230
11.1.3 Array.prototype.keys 232
11.1.4 Array.prototype.values 233
11.1.5 Array.prototype.entries 233
11.1.6 Array.prototype.copyWithin 234
11.1.7 Array.prototype.find 236
11.1.8 Array.prototype.findIndex 237
11.1.9 Array.prototype.fill 238
11.1.10 Array.prototype.includes 239
11.1.11 Array.prototype.flat 239
11.1.12 Array.prototype.flatMap 240
11.2 迭代、展开、解构 241
11.3 稳定的数组排序 241
11.4 类型化数组 241
11.4.1 概述 242
11.4.2 基本用法 243
11.4.3 ArrayBuffer:类型化数组使用的
存储方式 246
11.4.4 Endianness(字节序) 247
11.4.5 DataView:直接访问缓冲区 248
11.4.6 在数组间共享ArrayBuffer 250
11.4.7 类型化数组的子类 251
11.4.8 类型化数组方法 251
11.5 旧习换新 253
11.5.1 使用find和findIndex方法替代
循环来搜索数组(在适当的
情况下) 253
11.5.2 使用Array.fill替代循环
填充数组 254
11.5.3 使用readAsArrayBuffer
替代readAsBinaryString 254
第12章 Map和Set 255
12.1 Map 255
12.1.1 Map的基本操作 256
12.1.2 键的相等性 257
12.1.3 从可迭代对象中创建Map 258
12.1.4 迭代Map的内容 259
12.1.5 创建Map的子类 261
12.1.6 性能 261
12.2 Set 262
12.2.1 Set的基本操作 262
12.2.2 从可迭代对象中创建Set 263
12.2.3 迭代Set的内容 263
12.2.4 创建Set的子类 265
12.2.5 性能 265
12.3 WeakMap 265
12.3.1 WeakMap是不可迭代的 266
12.3.2 用例与示例 266
12.3.3 值反向引用键 269
12.4 WeakSet 274
12.5 旧习换新 276
12.5.1 在通用的映射中使用Map
替代对象 276
12.5.2 以Set替代对象作为集合 277
12.5.3 使用WeakMap存储私有数据,
而不是公共属性 277
第13章 模块 279
13.1 模块简介 279
13.2 模块的基本概念 280
13.2.1 模块说明符 281
13.2.2 基本命名导出 282
13.2.3 默认导出 283
13.2.4 在浏览器中使用模块 284
13.2.5 在Node.js中使用模块 287
13.3 重命名导出 289
13.4 重新导出另一个模块的导出 290
13.5 重命名导入 291
13.6 导入模块的命名空间对象 292
13.7 导出另一个模块的命名
空间对象 292
13.8 仅为副作用导入模块 293
13.9 导入和导出条目列表 293
13.9.1 导入条目列表 293
13.9.2 导出条目列表 294
13.10 导入是实时且只读的 295
13.11 模块实例具有领域特性 297
13.12 模块的加载方式 298
13.12.1 获取和解析 299
13.12.2 实例化 302
13.12.3 执行 302
13.12.4 暂时性死区(TDZ)回顾 303
13.12.5 循环依赖和TDZ 303
13.13 导入/导出语法回顾 304
13.13.1 不同的导出语法 304
13.13.2 不同的导入语法 305
13.14 动态导入 306
13.14.1 动态导入模块 306
13.14.2 动态模块示例 308
13.14.3 非模块脚本中的动态导入 311
13.15 摇树 312
13.16 打包 314
13.17 导入元数据 314
13.18 worker模块 315
13.18.1 将Web worker加载为模块 315
13.18.2 将Node.js worker加载为
模块 316
13.18.3 每个worker 都在自己的
领域中 316
13.19 旧习换新 316
13.19.1 使用模块替代伪命名空间 317
13.19.2 使用模块替代作用域函数 317
13.19.3 使用模块避免巨石代码
文件的创建 317
13.19.4 将CJS、AMD和其他模块
格式转换为ESM 318
13.19.5 使用维护良好的打包器,
而不是自研 318
第14章 反射和代理 319
14.1 反射 319
14.1.1 Reflect.apply 320
14.1.2 Reflect.construct 321
14.1.3 Reflect.ownKeys 322
14.1.4 Reflect.get和Reflect.set 322
14.1.5 其他Reflect函数 324
14.2 代理 324
14.2.1 示例:日志代理 326
14.2.2 代理劫持函数 334
14.2.3 示例:隐藏属性 342
14.2.4 可撤销代理 345
14.3 旧习换新 346
14.3.1 使用代理,而不是禁止消费侧
代码修改API对象 346
14.3.2 使用代理将实现代码与检测
代码分开 346
第15章 正则表达式更新 347
15.1 flags属性 347
15.2 新标志 348
15.2.1 粘连标志(y) 348
15.2.2 Unicode标志(u) 349
15.2.3 dot all标志(s) 349
15.3 命名捕获组 349
15.3.1 基本功能 350
15.3.2 反向引用 353
15.3.3 替换符号 354
15.4 反向预查 354
15.4.1 反向肯定预查 354
15.4.2 反向否定预查 355
15.4.3 反向预查中的贪婪匹配是
从右到左的 356
15.4.4 捕获组的编号和引用 356
15.5 Unicode特性 357
15.5.1 码点转义 357
15.5.2 Unicode属性转义 358
15.6 旧习换新 361
15.6.1 在解析时使用粘连标志(y),
而不是创建子字符串并使用
插入符(^) 361
15.6.2 使用dot all标志(s),而不是使用
一些变通方法匹配所有的字符
(包括换行符) 361
15.6.3 使用命名捕获组替代匿名
捕获组 362
15.6.4 使用反向预查替代各种
变通方法 362
15.6.5 在正则表达式中使用码点转义
替代代理对 363
15.6.6 使用Unicode模式替代
变通方法 363
第16章 共享内存 365
16.1 引言 365
16.2 务必谨慎 365
16.3 浏览器的支持 366
16.4 共享内存的基础知识 368
16.4.1 临界区、锁和条件变量 368
16.4.2 创建共享内存 369
16.5 共享的是内存,而不是对象 373
16.6 竞争条件、存储乱序、旧值、
撕裂等 374
16.7 Atomics对象 375
16.7.1 Atomics对象的底层特性 378
16.7.2 使用Atomics对象挂起和恢复
线程 379
16.8 共享内存示例 380
16.9 务必谨慎(再次) 399
16.10 旧习换新 404
16.10.1 使用共享内存块,而不是重复
交换大数据块 404
16.10.2 使用Atomics.wait和
Atomics.notify,而不是拆解
worker任务以支持事件循环
(在适当的地方) 404
第17章 其他特性 405
17.1 BigInt 406
17.1.1 创建BigInt 406
17.1.2 显式转换和隐式转换 407
17.1.3 性能 408
17.1.4 BigInt64Array和
BigUint64Array 408
17.1.5 工具函数 409
17.2 新的整数字面量 409
17.2.1 二进制整数字面量 409
17.2.2 八进制整数字面量,采用
ES2015新形式 410
17.3 新的Math方法 410
17.3.1 通用数学函数 410
17.3.2 提供底层操作的数学函数 411
17.4 取幂运算符(**) 412
17.5 Date.prototype.toString调整 413
17.6 Function.prototype.toString调整 413
17.7 Number扩展 414
17.7.1 “安全”整数 414
17.7.2 Number.isInteger 415
17.7.3 Number.isFinite和
Number.isNaN 415
17.7.4 Number.parseInt和
Number.parseFloat 416
17.7.5 Number.EPSILON 416
17.8 Symbol.isConcatSpreadable 416
17.9 其他语法微调 417
17.9.1 空值合并 417
17.9.2 可选链 418
17.9.3 省略catch绑定的异常 420
17.9.4 JSON中的Unicode行终止符 420
17.9.5 JSON.stringify输出符合语法
规则的JSON 420
17.10 标准库/全局对象的各类扩展 421
17.10.1 Symbol.hasInstance 421
17.10.2 Symbol.unscopables 421
17.10.3 globalThis 422
17.10.4 Symbol的description属性 422
17.10.5 String.prototype.matchAll 423
17.11 规范附录B:浏览器相关特性 423
17.11.1 类似HTML的注释 424
17.11.2 正则表达式微调 424
17.11.3 额外的内置属性 425
17.11.4 各种松散或晦涩的语法片段 427
17.11.5 当document.all不存在……
或存在 428
17.12 尾调用优化 429
17.13 旧习换新 431
17.13.1 使用二进制字面量 431
17.13.2 使用新的Math函数,而不是
各类数学变通方法 432
17.13.3 使用空值合并提供默认值 432
17.13.4 使用可选链替代&&检查 432
17.13.5 省略“catch(e)”中的
异常绑定 432
17.13.6 使用取幂运算符(**),
而不是Math.pow 433
第18章 即将推出的类特性 435
18.1 公有和私有的类字段、方法和
访问器 435
18.1.1 公有字段(属性)定义 436
18.1.2 私有字段 440
18.1.3 私有实例方法和访问器 446
18.1.4 公有静态字段、私有静态字段和
私有静态方法 450
18.2 旧习换新 452
18.2.1 使用属性定义,而不是在构造
函数中创建属性(在适当的
情况下) 452
18.2.2 使用私有类字段,而不是前缀
(在适当的情况下) 453
18.2.3 使用私有方法(而不是类外的
函数)进行私有操作 453
第19章 展望未来 457
19.1 顶层await 458
19.1.1 概述和用例 458
19.1.2 示例 459
19.1.3 错误处理 463
19.2 WeakRef和清理回调 464
19.2.1 WeakRef 464
19.2.2 清理回调 466
19.3 正则表达式匹配索引 471
19.4 String.prototype.replaceAll 472
19.5 Atomics的asyncWait方法 472
19.6 其他语法微调 473
19.6.1 数字分隔符 473
19.6.2 支持hashbang 474
19.7 废弃旧的正则表达式特性 474
19.8 感谢阅读 475
附录 出色的特性及对应的章
(向J.K. Rowling致歉) 477
新特性 1
1.1 名称、定义和术语 2
1.1.1 Ecma?ECMAScript?TC39? 2
1.1.2 ES6?ES7?ES2015?ES2020? 2
1.1.3 JavaScript“引擎”、浏览器及其他 3
1.2 什么是“新特性” 3
1.3 新特性的推动流程 5
1.3.1 谁负责 5
1.3.2 流程 5
1.3.3 参与 6
1.3.4 跟上新特性的步伐 7
1.4 旧环境中使用新特性 8
1.5 本章小结 12
第2章 块级作用域声明:let和const 13
2.1 let和const的介绍 13
2.2 真正的块级作用域 14
2.3 重复声明将抛出错误 15
2.4 提升和暂时性死区 15
2.5 一种新的全局变量 17
2.6 const:JavaScript的常量 19
2.6.1 const基础 19
2.6.2 常量引用的对象仍然是可变的 20
2.7 循环中的块级作用域 21
2.7.1 “循环中的闭包”问题 21
2.7.2 绑定:变量、常量以及其他
标识符的工作方式 23
2.7.3 while和do-while循环 27
2.7.4 性能影响 28
2.7.5 循环块中的const 29
2.7.6 for-in循环中的const 29
2.8 旧习换新 30
2.8.1 用const或let替代var 30
2.8.2 缩小变量的作用域 30
2.8.3 用块级作用域替代匿名函数 30
第3章 函数的新特性 33
3.1 箭头函数和this、super等词法 34
3.1.1 箭头函数语法 34
3.1.2 箭头函数和this词法 37
3.1.3 箭头函数不能被用作构造函数 38
3.2 默认参数值 38
3.2.1 默认值是表达式 39
3.2.2 默认值在自己的作用域中被计算 40
3.2.3 默认值不会增加函数的arity 42
3.3 “rest”参数 42
3.4 参数列表和函数调用中的
尾后逗号 44
3.5 函数的name属性 45
3.6 在语句块中声明函数 46
3.6.1 在语句块中声明函数:标准语义 48
3.6.2 在语句块中声明函数:
传统Web语义 49
3.7 旧习换新 51
3.7.1 使用箭头函数替代各种访问this
值的变通方式 51
3.7.2 在不使用this或arguments时,
回调函数使用箭头函数 52
3.7.3 考虑在更多地方使用箭头函数 52
3.7.4 当调用者需要控制this的值时,
不要使用箭头函数 53
3.7.5 使用参数默认值,而不是
代码实现 53
3.7.6 使用“rest”参数替代arguments
关键字 53
3.7.7 如有必要,考虑使用尾后逗号 53
第4章 类 55
4.1 类的概念 55
4.2 介绍新的类语法 56
4.2.1 添加构造函数 57
4.2.2 添加实例属性 59
4.2.3 添加原型方法 59
4.2.4 添加静态方法 61
4.3 添加访问器属性 61
4.4 对比新语法和旧语法 64
4.5 创建子类 66
4.6 关键字super 69
4.6.1 编写子类构造函数 69
4.6.2 继承和访问超类原型的属性和
方法 70
4.6.3 继承静态方法 73
4.6.4 静态方法中的super 75
4.6.5 返回新实例的方法 75
4.6.6 内置对象的子类 79
4.6.7 super的使用 81
4.7 移除Object.prototype 83
4.8 new.target 84
4.9 类声明与类表达式 87
4.9.1 类声明 87
4.9.2 类表达式 88
4.10 更多内容 89
4.11 旧习换新 89
第5章 对象的新特性 91
5.1 可计算属性名 91
5.2 属性的简写语法 92
5.3 获取和设置对象原型 93
5.3.1 Object.setPrototypeOf 93
5.3.2 浏览器环境中的__proto__属性 94
5.3.3 浏览器环境中的__proto__字面量
属性名 94
5.4 对象方法的简写语法,以及类
之外的super 95
5.5 Symbol 97
5.5.1 定义Symbol的原因 97
5.5.2 创建和使用Symbol 99
5.5.3 Symbol并不用于私有属性 99
5.5.4 全局Symbol 100
5.5.5 内置的Symbol值 103
5.6 对象的新增方法 104
5.6.1 Object.assign 104
5.6.2 Object.is 105
5.6.3 Object.values 105
5.6.4 Object.entries 106
5.6.5 Object.fromEntries 106
5.6.6 Object.getOwnPropertySymbols 106
5.6.7 Object.getOwnPropertyDescriptors 106
5.7 Symbol.toPrimitive 107
5.8 属性顺序 109
5.9 属性扩展语法 110
5.10 旧习换新 111
5.10.1 创建对象时对动态变量使用可
计算属性名 111
5.10.2 从同名变量初始化对象时,
使用简写语法 111
5.10.3 使用Object.assign替代自定义的
扩展方法或者显式复制所有
属性 112
5.10.4 基于已有对象创建新对象时,
使用属性扩展语法 112
5.10.5 使用Symbol避免属性名冲突 112
5.10.6 使用Object.getPrototypeOf/
setPrototypeOf替代__proto__ 112
5.10.7 使用对象方法的简写语法来
定义对象中的方法 112
第6章 可迭代对象、迭代器、for-of循环、
可迭代对象的展开语法和
生成器 115
6.1 迭代器、可迭代对象、for-of循环,
以及可迭代对象的展开语法 115
6.1.1 迭代器和可迭代对象 115
6.1.2 for-of循环:隐式地使用迭代器 116
6.1.3 显式地使用迭代器 117
6.1.4 提前停止迭代 118
6.1.5 迭代器的原型对象 119
6.1.6 使对象可迭代 121
6.1.7 使迭代器可迭代 124
6.1.8 可迭代对象的展开语法 126
6.1.9 迭代器、for-of循环和DOM 127
6.2 生成器函数 129
6.2.1 仅生成值的基本生成器函数 129
6.2.2 使用生成器函数创建迭代器 130
6.2.3 生成器函数作为方法 131
6.2.4 直接使用生成器 132
6.2.5 用生成器消费值 132
6.2.6 在生成器函数中使用return 136
6.2.7 yield运算符的优先级 136
6.2.8 return和throw方法:终止
生成器 137
6.2.9 生成生成器或者可迭代对象:
yield* 139
6.3 旧习换新 143
6.3.1 使用消费可迭代对象的结构 143
6.3.2 使用DOM集合的可迭代特性 144
6.3.3 使用可迭代对象和迭代器接口 144
6.3.4 在过去用Function.prototype.apply
的大部分场景中使用可迭代对象
的展开语法 144
6.3.5 使用生成器 144
第7章 解构 145
7.1 概览 145
7.2 基础的对象解构 145
7.3 基础的数组(和可迭代对象)的
解构 148
7.4 解构默认值 150
7.5 解构匹配模式中的“rest”语法 151
7.6 使用不同的名称 152
7.7 可计算属性名 153
7.8 嵌套解构 153
7.9 参数解构 154
7.10 循环中的解构 157
7.11 旧习换新 157
7.11.1 仅从对象获取某些属性时
使用解构 158
7.11.2 对可选项对象使用解构 158
第8章 Promise 159
8.1 为什么要使用Promise 159
8.2 Promise基础 160
8.2.1 概览 160
8.2.2 示例 161
8.2.3 Promise和thenable对象 163
8.3 使用已存在的Promise 163
8.3.1 then方法 163
8.3.2 链式Promise 164
8.3.3 对比Promise链与回调函数 168
8.3.4 catch方法 168
8.3.5 finally方法 170
8.3.6 在then、catch和finally处理程序
中抛出异常 173
8.3.7 带有两个参数的then方法 175
8.4 为已敲定状态的Promise添加
处理程序 176
8.5 创建Promise 177
8.5.1 Promise构造函数 178
8.5.2 Promise.resolve 180
8.5.3 Promise.reject 181
8.6 其他Promise工具方法 182
8.6.1 Promise.all 182
8.6.2 Promise.race 183
8.6.3 Promise.allSettled 184
8.6.4 Promise.any 184
8.7 Promise的模式 185
8.7.1 处理错误或返回Promise 185
8.7.2 串行Promise 185
8.7.3 并行Promise 187
8.8 Promise的反模式 188
8.8.1 不必要的new Promise(/*…*/) 188
8.8.2 未处理的错误(或不正确的
处理方式) 188
8.8.3 在转换回调函数API时隐藏了
错误 188
8.8.4 隐式地将已拒绝状态转换为已
成功状态 189
8.8.5 试图在链式调用外使用结果 190
8.8.6 使用无用的处理程序 190
8.8.7 错误地处理链式调用分支 191
8.9 Promise的子类 192
8.10 旧习换新 193
第9章 异步函数、迭代器和生成器 195
9.1 async函数 195
9.1.1 async函数创建Promise对象 197
9.1.2 await接收Promise 198
9.1.3 异步是使用await的常规思维
方式 199
9.1.4 拒绝即异常,异常即拒绝;成功值
就是结果,返回值就是决议 200
9.1.5 async函数中的并行操作 202
9.1.6 不必使用return await 203
9.1.7 陷阱:在意想不到的地方使用
async函数 204
9.2 异步迭代器、可迭代对象和
生成器 205
9.2.1 异步迭代器 205
9.2.2 异步生成器 208
9.2.3 for-await-of 209
9.3 旧习换新 210
第10章 模板字面量、标签函数和新的
字符串特性 211
10.1 模板字面量 211
10.1.1 基本功能(不带标签的模板
字面量) 212
10.1.2 模板标签函数(带标签的模板
字面量) 213
10.1.3 String.raw 218
10.1.4 模板字面量的复用 219
10.1.5 模板字面量和自动分号插入 219
10.2 改进的Unicode支持 219
10.2.1 Unicode以及JavaScript字符串的
含义 219
10.2.2 码点转义序列 221
10.2.3 String.fromCodePoint 221
10.2.4 String.prototype.codePointAt 221
10.2.5 String.prototype.normalize 222
10.3 迭代 223
10.4 新的字符串方法 224
10.4.1 String.prototype.repeat 224
10.4.2 String.prototype.startsWith和
endsWith 224
10.4.3 String.prototype.includes 225
10.4.4 String.prototype.padStart和
padEnd 225
10.4.5 String.prototype.trimStart和
trimEnd 226
10.5 match、split、search和replace
方法的更新 226
10.6 旧习换新 228
10.6.1 使用模板字面量替代字符串
连接(在适当的情况下) 228
10.6.2 对DSL使用标签函数和模板
字面量,而不是自动占位符
机制 228
10.6.3 使用字符串迭代 228
第11章 新数组特性、类型化数组 229
11.1 新的数组方法 229
11.1.1 Array.of 229
11.1.2 Array.from 230
11.1.3 Array.prototype.keys 232
11.1.4 Array.prototype.values 233
11.1.5 Array.prototype.entries 233
11.1.6 Array.prototype.copyWithin 234
11.1.7 Array.prototype.find 236
11.1.8 Array.prototype.findIndex 237
11.1.9 Array.prototype.fill 238
11.1.10 Array.prototype.includes 239
11.1.11 Array.prototype.flat 239
11.1.12 Array.prototype.flatMap 240
11.2 迭代、展开、解构 241
11.3 稳定的数组排序 241
11.4 类型化数组 241
11.4.1 概述 242
11.4.2 基本用法 243
11.4.3 ArrayBuffer:类型化数组使用的
存储方式 246
11.4.4 Endianness(字节序) 247
11.4.5 DataView:直接访问缓冲区 248
11.4.6 在数组间共享ArrayBuffer 250
11.4.7 类型化数组的子类 251
11.4.8 类型化数组方法 251
11.5 旧习换新 253
11.5.1 使用find和findIndex方法替代
循环来搜索数组(在适当的
情况下) 253
11.5.2 使用Array.fill替代循环
填充数组 254
11.5.3 使用readAsArrayBuffer
替代readAsBinaryString 254
第12章 Map和Set 255
12.1 Map 255
12.1.1 Map的基本操作 256
12.1.2 键的相等性 257
12.1.3 从可迭代对象中创建Map 258
12.1.4 迭代Map的内容 259
12.1.5 创建Map的子类 261
12.1.6 性能 261
12.2 Set 262
12.2.1 Set的基本操作 262
12.2.2 从可迭代对象中创建Set 263
12.2.3 迭代Set的内容 263
12.2.4 创建Set的子类 265
12.2.5 性能 265
12.3 WeakMap 265
12.3.1 WeakMap是不可迭代的 266
12.3.2 用例与示例 266
12.3.3 值反向引用键 269
12.4 WeakSet 274
12.5 旧习换新 276
12.5.1 在通用的映射中使用Map
替代对象 276
12.5.2 以Set替代对象作为集合 277
12.5.3 使用WeakMap存储私有数据,
而不是公共属性 277
第13章 模块 279
13.1 模块简介 279
13.2 模块的基本概念 280
13.2.1 模块说明符 281
13.2.2 基本命名导出 282
13.2.3 默认导出 283
13.2.4 在浏览器中使用模块 284
13.2.5 在Node.js中使用模块 287
13.3 重命名导出 289
13.4 重新导出另一个模块的导出 290
13.5 重命名导入 291
13.6 导入模块的命名空间对象 292
13.7 导出另一个模块的命名
空间对象 292
13.8 仅为副作用导入模块 293
13.9 导入和导出条目列表 293
13.9.1 导入条目列表 293
13.9.2 导出条目列表 294
13.10 导入是实时且只读的 295
13.11 模块实例具有领域特性 297
13.12 模块的加载方式 298
13.12.1 获取和解析 299
13.12.2 实例化 302
13.12.3 执行 302
13.12.4 暂时性死区(TDZ)回顾 303
13.12.5 循环依赖和TDZ 303
13.13 导入/导出语法回顾 304
13.13.1 不同的导出语法 304
13.13.2 不同的导入语法 305
13.14 动态导入 306
13.14.1 动态导入模块 306
13.14.2 动态模块示例 308
13.14.3 非模块脚本中的动态导入 311
13.15 摇树 312
13.16 打包 314
13.17 导入元数据 314
13.18 worker模块 315
13.18.1 将Web worker加载为模块 315
13.18.2 将Node.js worker加载为
模块 316
13.18.3 每个worker 都在自己的
领域中 316
13.19 旧习换新 316
13.19.1 使用模块替代伪命名空间 317
13.19.2 使用模块替代作用域函数 317
13.19.3 使用模块避免巨石代码
文件的创建 317
13.19.4 将CJS、AMD和其他模块
格式转换为ESM 318
13.19.5 使用维护良好的打包器,
而不是自研 318
第14章 反射和代理 319
14.1 反射 319
14.1.1 Reflect.apply 320
14.1.2 Reflect.construct 321
14.1.3 Reflect.ownKeys 322
14.1.4 Reflect.get和Reflect.set 322
14.1.5 其他Reflect函数 324
14.2 代理 324
14.2.1 示例:日志代理 326
14.2.2 代理劫持函数 334
14.2.3 示例:隐藏属性 342
14.2.4 可撤销代理 345
14.3 旧习换新 346
14.3.1 使用代理,而不是禁止消费侧
代码修改API对象 346
14.3.2 使用代理将实现代码与检测
代码分开 346
第15章 正则表达式更新 347
15.1 flags属性 347
15.2 新标志 348
15.2.1 粘连标志(y) 348
15.2.2 Unicode标志(u) 349
15.2.3 dot all标志(s) 349
15.3 命名捕获组 349
15.3.1 基本功能 350
15.3.2 反向引用 353
15.3.3 替换符号 354
15.4 反向预查 354
15.4.1 反向肯定预查 354
15.4.2 反向否定预查 355
15.4.3 反向预查中的贪婪匹配是
从右到左的 356
15.4.4 捕获组的编号和引用 356
15.5 Unicode特性 357
15.5.1 码点转义 357
15.5.2 Unicode属性转义 358
15.6 旧习换新 361
15.6.1 在解析时使用粘连标志(y),
而不是创建子字符串并使用
插入符(^) 361
15.6.2 使用dot all标志(s),而不是使用
一些变通方法匹配所有的字符
(包括换行符) 361
15.6.3 使用命名捕获组替代匿名
捕获组 362
15.6.4 使用反向预查替代各种
变通方法 362
15.6.5 在正则表达式中使用码点转义
替代代理对 363
15.6.6 使用Unicode模式替代
变通方法 363
第16章 共享内存 365
16.1 引言 365
16.2 务必谨慎 365
16.3 浏览器的支持 366
16.4 共享内存的基础知识 368
16.4.1 临界区、锁和条件变量 368
16.4.2 创建共享内存 369
16.5 共享的是内存,而不是对象 373
16.6 竞争条件、存储乱序、旧值、
撕裂等 374
16.7 Atomics对象 375
16.7.1 Atomics对象的底层特性 378
16.7.2 使用Atomics对象挂起和恢复
线程 379
16.8 共享内存示例 380
16.9 务必谨慎(再次) 399
16.10 旧习换新 404
16.10.1 使用共享内存块,而不是重复
交换大数据块 404
16.10.2 使用Atomics.wait和
Atomics.notify,而不是拆解
worker任务以支持事件循环
(在适当的地方) 404
第17章 其他特性 405
17.1 BigInt 406
17.1.1 创建BigInt 406
17.1.2 显式转换和隐式转换 407
17.1.3 性能 408
17.1.4 BigInt64Array和
BigUint64Array 408
17.1.5 工具函数 409
17.2 新的整数字面量 409
17.2.1 二进制整数字面量 409
17.2.2 八进制整数字面量,采用
ES2015新形式 410
17.3 新的Math方法 410
17.3.1 通用数学函数 410
17.3.2 提供底层操作的数学函数 411
17.4 取幂运算符(**) 412
17.5 Date.prototype.toString调整 413
17.6 Function.prototype.toString调整 413
17.7 Number扩展 414
17.7.1 “安全”整数 414
17.7.2 Number.isInteger 415
17.7.3 Number.isFinite和
Number.isNaN 415
17.7.4 Number.parseInt和
Number.parseFloat 416
17.7.5 Number.EPSILON 416
17.8 Symbol.isConcatSpreadable 416
17.9 其他语法微调 417
17.9.1 空值合并 417
17.9.2 可选链 418
17.9.3 省略catch绑定的异常 420
17.9.4 JSON中的Unicode行终止符 420
17.9.5 JSON.stringify输出符合语法
规则的JSON 420
17.10 标准库/全局对象的各类扩展 421
17.10.1 Symbol.hasInstance 421
17.10.2 Symbol.unscopables 421
17.10.3 globalThis 422
17.10.4 Symbol的description属性 422
17.10.5 String.prototype.matchAll 423
17.11 规范附录B:浏览器相关特性 423
17.11.1 类似HTML的注释 424
17.11.2 正则表达式微调 424
17.11.3 额外的内置属性 425
17.11.4 各种松散或晦涩的语法片段 427
17.11.5 当document.all不存在……
或存在 428
17.12 尾调用优化 429
17.13 旧习换新 431
17.13.1 使用二进制字面量 431
17.13.2 使用新的Math函数,而不是
各类数学变通方法 432
17.13.3 使用空值合并提供默认值 432
17.13.4 使用可选链替代&&检查 432
17.13.5 省略“catch(e)”中的
异常绑定 432
17.13.6 使用取幂运算符(**),
而不是Math.pow 433
第18章 即将推出的类特性 435
18.1 公有和私有的类字段、方法和
访问器 435
18.1.1 公有字段(属性)定义 436
18.1.2 私有字段 440
18.1.3 私有实例方法和访问器 446
18.1.4 公有静态字段、私有静态字段和
私有静态方法 450
18.2 旧习换新 452
18.2.1 使用属性定义,而不是在构造
函数中创建属性(在适当的
情况下) 452
18.2.2 使用私有类字段,而不是前缀
(在适当的情况下) 453
18.2.3 使用私有方法(而不是类外的
函数)进行私有操作 453
第19章 展望未来 457
19.1 顶层await 458
19.1.1 概述和用例 458
19.1.2 示例 459
19.1.3 错误处理 463
19.2 WeakRef和清理回调 464
19.2.1 WeakRef 464
19.2.2 清理回调 466
19.3 正则表达式匹配索引 471
19.4 String.prototype.replaceAll 472
19.5 Atomics的asyncWait方法 472
19.6 其他语法微调 473
19.6.1 数字分隔符 473
19.6.2 支持hashbang 474
19.7 废弃旧的正则表达式特性 474
19.8 感谢阅读 475
附录 出色的特性及对应的章
(向J.K. Rowling致歉) 477
猜您喜欢