《深入理解现代JavaScript》中,“新特性”是指在 ES2015~ES2020 中添加到 JavaScript 的特性 ( 包含一部分即将到来的新特性) 。在这 6 次更新中, JavaScript 有了很大的进步。下面给出了一个总体概述 ( 规范附录 A 有一个更完整的更新列表) 。你可能不熟悉列表中的部分术语,不必担心,你将在本书的学习过程中了解它们。
——————————————————————————
1 https://www.electronjs.org/ 。
2 https://reactnative.dev/ 。
3 https://nodejs.org/ 。
——————————————————————————
● 块作用域 (let , const) :变量作用域更小,对 for 循环中作用域的巧妙处理,值不能改变的“变
量” (const) 。
● “箭头”函数:轻量、简洁的函数,在回调函数场景特别有用,因为箭头函数对 this 进行了
封装,而不是在调用时设置 this 值。
● 函数参数的改进:默认值、参数解构、“ rest ”参数、尾后逗号。
● 可迭代对象:为创建和消费可迭代对象 ( 如数组和字符串 ) 定义了清晰的语义,语言中的迭代结
构 (for-of 、 for-await-of) ,用于生成可迭代序列 ( 包括异步序列 ) 的生成器函数。
● “展开”语法:将数组 ( 或其他可迭代对象 ) 条目展开到新的数组中,将对象属性展开到新的对
象中,将可迭代对象的条目展开成函数离散参数,特别适合用于函数式编程或其他使用不可
改变的结构的地方。
● “ rest ”语法:把一个对象的“剩余”属性、一个可迭代对象的“剩余”值或一个函数的“剩
余”参数合成一个对象或数组。
● 其他语法改进:调用函数时允许在参数列表中使用尾后逗号;在 catch 中省略未使用的标识符;
新的八进制字面量;二进制字面量;数字字面量中的分隔符;等等。
● 解构:用比对象和数组字面量语法更简洁的方式从数组 / 对象中选值。
● 类:创建构造函数和相关原型对象的明显更简单的声明式语法,同时保留了 JavaScript 固有的
原型本质。
● 异步编程的改进: Promise 、 async 函数和 await ;显著地减少了“回调地狱”。
● 对象字面量的改进:可计算属性名、属性的简写语法、方法语法、属性定义后的尾后逗号。
● 模板字面量:创建有动态内容的字符串的一种简单、声明式的语法,也可用于创建更强大的
标签模板函数。
● 类型化数组:为使用本地 API( 以及更多能力 ) 而建立的底层真正的数组。
● 共享内存:在 JavaScript 线程 ( 包括线程间协调原语 ) 之间真正共享内存的能力。
● Unicode 字符串的改进: Unicode 码点转义序列,支持获取码点,而不是代码单元。
● 正则表达式的改进:反向预查,命名捕获组,匹配索引, Unicode 属性转义, Unicode 不区分
大小写。
● Map :键 / 值对集合,其中键不一定是字符串。
● Set :语义清晰的唯一值的集合。
● WeakMap 、 WeakSet 和 WeakRef :仅持有对象的弱引用的内置对象 ( 允许对象被当作垃圾收集 ) 。
● 标准库扩展: Object 、 Array 、 Array.prototype 、 String 、 String.prototype 、 Math 等的新方法。
● 动态元编程的支持: Proxy 和 Reflect 。
● Symbol :保证唯一的值 ( 对唯一的属性名特别有用 ) 。
● BigInt :任意精度的整数。
● 还有许多其他的特性。
所有这些新特性,尤其是新语法,可能会让人不知所措和焦虑。不用担心!除非你已经准备好并
有实际需求,否则没必要采用新特性。 TC39 坚持的主要原则之一是“别毁坏 Web ” (Don’t break the web) 。
这意味着 JavaScript 必须保持“ Web 兼容”,也就是与现在已经存在的大量代码兼容 1 。如果你不需要 或不喜欢一个新特性,则不必使用它。你使用对应旧语法编写的代码将始终有效。但在很多情况下, 你可能会发现你完全有理由使用新特性,尤其是新的语法功能:它们使一些东西的编写和理解变得更 简单,更不容易出错,或者在 Proxy 和 WeakMap/WeakSet、共享内存和其他情况下,它们使一些之前难以实现的功能成为可能。
——————————————————————————
1 委员会也关注与 Web 没有直接关系的重要 JavaScript 代码。
——————————————————————————
由于篇幅原因,本书仅涵盖 JavaScript 规范 ECMA-262 中的新特性。但是 ECMA-402
(ECMAScript 国际化 API 规范 ) 中也有一些令人兴奋的新特性,非常值得一读。你可在本书的网站上找到有关 ECMA-402 的部分,网址是 https://thenewtoys.dev/internationalization 。
新特性的推动流程
下面将介绍由谁负责推动 JavaScript 的发展,他们用什么流程来推动,以及如何跟踪和参与这个
流程。
谁负责
前面介绍过, TC39 技术委员会负责创建和发布 ECMAScript 标准的更新规范。该委员会的成员
包括: JavaScript 开发者、框架作者、大型网站作者 / 维护人员、编程语言研究人员、所有主要 JavaScript 引擎的代表、有影响力的 JavaScript 编程人员以及其他与 JavaScript 的成功与未来有关的人。他们有 定期的会议,历史上每年召开 6 次会议,每次持续 3 天。如果想以成员身份参加会议,你所在的组织 需要加入 Ecma 1 。开发者需求、实现复杂度、安全问题、向后兼容性以及许多其他的设计输入都是复 杂问题,TC39 会综合考虑这些问题,为 JavaScript 社区设计出有用的新特性。
为确保委员会是社区的一部分而不脱离社区, TC39 在 GitHub 上创建了 ecma262 仓库 2 ,其中有
最新的规范 ( 可在 https://tc39.es/ecma262/ 上查看 ) ;它还创建了一个提案仓库 3 ,用于维护需要通过 TC39 流程( 下一节介绍 ) 的提案。一些成员还活跃在 TC39 论坛小组 4 中。 TC39 会议的记录和相关材料 ( 幻灯 片等) 都会发布在 https://github.com/tc39/notes 上。
你可访问 https://tc39.es/ ,了解更多关于 TC39 以及如何参与的信息;还可在
https://github.com/tc39/how-we-work 上了解更多关于 TC39 工作方式的信息。
流程
TC39 在 2013 年 11 月通过了一个定义明确的流程,并在 2014 年 1 月首次公布。该流程有多个阶
段, TC39 使提案经历这些阶段 ( 从阶段 0 到阶段 4) 。每个阶段都有明确的预期,并明确指出从一个阶段进入下一个阶段的标准。一旦一个提案符合进入下一阶段的标准,委员会就会以协商一致的方式决 定是否将其向前推进。
流程文档 5 本身值得一读,但简单而言,共有以下这些阶段。
● 阶段 0 —— Strawperson :任何觉得自己的想法值得考虑的人都可将它写下来,然后提出来。
这几乎不能被称为一个阶段,因为想法可能随时变化。如果提出建议的人不是 TC39 成员,
则需要注册为非成员贡献者 6 ( 任何人都可这样做 ) 。最终,只有一部分提案会被列入 TC39 的
提案仓库中,而有些则不会,通常只有那些获得委员会成员支持的提案才能进入提案仓库。
——————————————————————————
1 https://ecma-international.org/memento/join.htm 。
2 https://github.com/tc39/ecma262 。
3 https://github.com/tc39/proposals 。
4 https://es.discourse.group/ 。
5 https://tc39.es/process-document/ 。
6 https://tc39.es/agreements/contributor/ 。
——————————————————————————
如果这一阶段的提案引起了足够的关注, TC39 的成员可能会把它加入 TC39 会议的议程中,
以讨论并考虑是否使其进入阶段 1 。
● 阶段 1 —— Proposal :如果一个提案被提交给委员会,且委员会一致认为应进一步调查,他们
就会将其转入阶段 1 ,并指定一名评委来指导整个流程。如果该提案尚无 GitHub 仓库,则需
要由发起人、评委或其他感兴趣的第三方创建一个。然后,社区成员 ( 无论是否在委员会中 )
将进一步讨论和补充该想法,研究其他语言或环境中类似的技术,细化范围,找出通用解决
方案,并充实这个想法。这一步的结果可能是,该提案收益比偏低,不值得继续推进;或者
该想法需要分解并添加到其他提案中;等等。但是,如果该提案有价值,相关人员 ( 可能随着
时间的推移人员会发生变化 ) 将把一些初步的规范语言、 API 和语义草案一并提交给 TC39 ,
以便他们考虑是否进入阶段 2 。
● 阶段 2 —— Draft :准备就绪后,相关人员将在 TC39 会议上提交阶段 1 的提案,审议是否进入
阶段 2 。这意味着 TC39 要就该提案是否继续进行达成共识,并期望该提案最终被纳入规范。
在这个阶段,社区会完善精确的语法、语义、 API 等并使用正式的规范语言详细描述解决方
案。通常,相关人员会在这个阶段创建 polyfill 或 Babel 插件,以便实际试用。提案可能会在
阶段 2 停留一段时间,因为需要解决一些细节问题。
● 阶段 3 —— Candidate :一旦团队确定了提案的最终草案形式并为其创建了正式的规范语言,
评委就可将其提交到阶段 3 。这意味着 TC39 会就该提案是否已准备好在 JavaScript 引擎中实
现这一问题寻求共识。在这个阶段,提案本身几乎是稳定的。此时的更改将仅限于对该提案
实现的反馈,例如在实现过程中发现的极端情况、 Web 兼容性问题或实现复杂度。
● 阶段 4 —— Finished :至此,该特性已完成,可被添加到编辑草案中,网址是
https://tc39.es/ecma262/ 。要到达这个最后阶段,该特性必须在 TC39 的 test262 测试套件 1 中进
行验收测试;且至少要有两个通过测试的兼容实现 ( 例如, Chrome Canary 的 V8 和 Firefox
Nightly 的 SpiderMonkey ,或 Firefox 的 SpiderMonkey 版本和 Safari 技术预览版的 JavaScriptCore
等 ) 。满足这些条件后,该特性的开发团队将发送 PR(pull request) 到 ecma262 仓库,并将规范的
变化纳入编辑草案, ECMAScript 审校组将接受该 PR 。至此,提案便进入阶段 4 了。
这就是提案成为 JavaScript 的一部分所要经历的流程,但并不是每个更改都是一个提案。相关人
员在 TC39 会议上针对规范的 PR 达成的共识可实现较小的更改。例如, Date.prototype.toString 的输出 在 ES2017 和 ES2018 之间发生的变化 ( 请参见第 17 章 ) ,就是相关人员对 PR( 而不是经历不同阶段的 提案) 达成共识的结果。通常这些更改是编辑草案的更改,或者是 JavaScript 引擎已实现但未包含在规 范中的更改,也可能是规范要求的并被 TC39 认为可取而且做到了“ Web 兼容” ( 不会破坏大量现有 代码) 的改动,例如 ES2019 中的更改,它使 Array.prototype.sort 成为稳定的排序 ( 请参见第 11 章 ) 。如果你想了解哪些更改计划或者已经以这种方式进行,请查看https://github.com/tc39/ecma262 仓库 ( 同样,对于 ECMA-402 的更改,请查看 https://github.com/tc39/ecma402) 中的“ needs consensus ”标签。要找
到已完成的变更,请查看“ has consensus ”“ editorial change ”和“ normative change ”标签。在某些时
候,这些以“ needs consensus ”为标签的更改可能会采用更正式的流程,但目前你可通过这种方式查 看它们。
参与
如果你看到一个感兴趣的提案,想参与其中,那么你应该何时参与?参与的流程应该是怎样的?
——————————————————————————
1 https://github.com/tc39/test262 。
——————————————————————————
重要的是尽早参与。提案进入阶段 3 后,相关人员通常仅考虑基于实现过程的重大问题。参与的
最佳时机在阶段 0 、阶段 1 和阶段 2 。在这几个阶段,你可根据自己的经验提供见解,帮助定义语义, 使用 Babel 之类的工具尝试提议的内容等。这并不是说你在阶段 3 的提案中起不到什么作用 ( 有时候有一些任务,比如确定规范文本或者帮忙编写开发者文档) ,只是要注意,在阶段 3 提出的修改建议 通常没什么用,除非你是在 JavaScript 引擎中实现此提案的人之一。
如果你已经找到了一个你想参与的提案,该怎么办?这取决于你,但这里有一些建议。
● 充分调研。 请仔细阅读提案的说明 (TC39 提案列表链接的 README.md) 和其他相关文档。如
果其中提到了现有技术 ( 如另一种语言中的类似特性 ) ,则应仔细阅读那项现有技术。如果有
最初的规范文档,请阅读它 ( 该指南可能会有帮助: https://timothygu.me/es-howto/) 。请确保你
提供的意见是有根据的。
● 试用该特性! 即使你还不能使用它,也可以写一些推测性代码 ( 你无法运行,但可以思考的代
码 ) 来评估该提案在多大程度上能解决它计划要解决的问题。如果有相应的 Babel 插件,可尝
试编写并运行代码。查看该特性的执行结果并提供反馈。
● 寻找你可以参与的方式。 除了建议和反馈之外,还有很多方法可让你参与到提案的改进中。
例如,你可以寻找那些已达成共识,但没有人有时间去解决的问题 ( 研究已存在的技术,更新
说明文档和规范文档 ) 。如果你愿意,可以做这些事情。你可通过 GitHub 的 issue 讨论提案,
从而与提案作者协调。
参与过程中,请尊重每个人,并保持友好、耐心、包容和体贴的心态。要注意措辞。与其表现出
反对、轻视或阻挠的态度,不如善待他人并表现出合作精神,这样,你更有可能产生影响。请注意, TC39 的会议和用于制定提案的线上空间均受《行为准则》 1 约束。请将不当行为提交给 TC39 的行为 准则委员会( 见链接文档 ) 。
跟上新特性的步伐
事实上,你不必紧跟 JavaScript 的新特性,因为如前所述,之前的语法不会消失。但是,如果你
正在阅读本书,那么我猜你一定想跟上新特性的步伐。
在阅读前面有关 TC39 流程的内容时,你可能感到困惑:该流程保证了新特性在被添加到规范中
之前就能使用。然而, 2009 年问世的 ES5 和 2015 年问世的 ES2015 描述的大部分特性在当时的任何 JavaScript 引擎中都不存在。如果规范的确定在新特性出来之后,那如何才能紧跟新的特性呢?下面 给出了一些方法。
● 关注 GitHub 上的提案仓库 (https://github.com/tc39/proposals) 。如果提案进入阶段 3 ,则可能会
在一两年内被添加到规范中。即使是处于阶段 2 的特性,最后也有可能被添加到规范中,不
过任何特性都可能在任何阶段被 TC39 拒绝。
● 阅读发布在 https://github.com/tc39/notes 上的 TC39 的会议记录。
● 参加 TC39 论坛小组 (https://es.discourse.group/) 2 。
● 注意下一节中讨论的工具的使用情况。
站点 https://thenewtoys.dev 将持续更新即将出现的新特性,敬请关注。
——————————————————————————
1 https://tc39.es/code-of-conduct/ 。
2 讨论小组在很大程度上取代了非正式讨论邮件列表。该列表仍然存在,但 TC39 的许多代表建议避免使用。
——————————————————————————
旧环境中使用新特性
如果仅学习本书中涵盖的特性,你不必担心如何处理不支持这些特性的环境。当前最新版本的
Chrome 、 Firefox 、 Safari 、 Edge 桌面浏览器以及 Node.js 几乎支持本书的所有内容 ( 第 18 和 19 章除外 ) 。
我们使用其中之一运行代码即可。
使用 Node.js 运行示例
默认情况下,当你使用 Node.js 运行脚本时,如下所示:
node script.js
代码在模块作用域 ( 而不是全局作用域 ) 内运行。本书中一些示例的演示仅在全局作用域内生效,
因此当你以这种方式运行代码时,它们将不起作用。
对于这些示例,请使用浏览器运行代码,或使用 Node.js 的交互式解释器 (REPL) 。要使用 REPL ,
不必为 node 命令的运行参数指定脚本文件,而是使用 < 运算符将脚本文件重定向到其中 ( 这在 UNIX/
Linux/Mac OS 系统和 Windows 上均有效 ) 。
node < script.js
在此要提醒的是,需要在全局作用域内运行示例时再执行此操作。
不过,在某个阶段,你可能想在不支持新特性的环境中使用它们。例如,大多数 JavaScript 开发
工作仍基于 Web 浏览器,不同浏览器中的 JavaScript 引擎对新特性的支持情况不同 (Internet Explorer
甚至不支持本书讨论的任何新特性 1 ,但目前它仍然占据了一部分全球市场份额,尤其是在政府和大 型公司内部网中) 。
当 ES5 发布时,确实存在这个问题,因为只有很少一部分新特性在当时发布的 JavaScript 引擎中
得以支持。但是 ES5 的大多数特性都是新的标准库特性,而在语法上没有显著的更改,因此可使用 es5-shim.js2 、 core-js 3 、 es-shims 4 等各种项目来 polyfill( 引入一个额外的脚本来提供缺少的对象 / 函数 ) 。
不过,在 2010 — 2015 年的 ES2015 开发过程中,很明显,要做好新语法的开发工作,就必须具备新 语法的实际开发经验,但是 JavaScript 的实现尚没有支持新语法,这显然是自相矛盾的。
工具制造者解决了这个问题!他们创建了 Traceur 5 和 Babel 6 ( 以前被称为 6to5) 等工具,这些工具以 使用新语法的源代码作为输入,将其转换为使用旧语法的代码,然后输出旧语法风格的代码( 还可选 择使用 polyfills 和其他运行时支持方法 ) 。类似地, TypeScript 7 在规范完成之前就支持 ES2015 的主要 部分。这些工具使你可以编写新语法风格的代码,但在将其交付到旧环境之前需要将其转换为旧语法 风格的代码。这种转换过程被称为“编译”或“转译”。这最初是为了方便对 ES2015 计划中的 JavaScript 改进进行反馈,但即使在 ES2015 出来以后,如果你计划在不支持新特性的环境中运行新语法风格的 代码,它也是一种编写新风格代码的有用方法。
——————————————————————————
1 至少支持不充分,它有一个不完整的 let 和 const 版本。
2 https://github.com/es-shims/es5-shim 。
3 https://github.com/zloirock/core-js 。
4 https://github.com/es-shims/ 。
5 https://github.com/google/traceur-compiler 。
6 http://babeljs.io/ 。
7 http://typescriptlang.org/ 。
——————————————————————————
在我撰写本文时, Traceur 已经销声匿迹了,但 Babel 却被全球很大一部分的 JavaScript 开发者所
使用。 Babel 几乎对 TC39 流程中的所有特性都进行了转换,甚至包括那些处于阶段 1 的特性,这些 特性在进入下一个流程前可能会有明显的变化( 因此,使用这些特性时需要自担风险。阶段 3 以上的特性要相对安全些) 。选择你想要使用的转换插件,使用这些特性编写代码, Babel 会生成可在不支持 这些特性的环境中使用的代码。
用 Babel 编译的示例
本节将简单介绍如何通过 Babel 将使用 ES2015 特性 ( 箭头函数 ) 的代码编译成可在 IE11 上运行的
兼容 ES5 的代码。但这只是一个例子,你也可轻松地通过 Babel 将使用阶段 3 特性的代码转换为兼容 ES2020 的代码,而这些特性尚未出现在任何已发布的 JavaScript 引擎中。 Babel 甚至还支持那些根本 不在 TC39 流程中的特性转换,例如 JSX 1 ( 在某些 JavaScript 框架中使用,主要是 React 2 ) 。富有冒险精 神的人可编写自己的转换插件,只用于他们的项目!
安装 Babel 前,你需要有 Node.js 和 npm(Node Package Manager) 。如果你尚未在系统上安装它们, 请执行以下任一操作。
(1) 在官网 https://nodejs.org/ 上查找适合你系统的安装程序 / 软件包并安装。
(2) 使用 NVM(Node Version Manager) ,该工具提供了一种方便的方法来安装多个 Node 版本并在
它们之间进行切换: https://github.com/nvm-sh/nvm 。
npm 与 Node.js 捆绑在一起,因此不必单独安装它。
安装完成后,请执行以下操作。
(1) 为此示例创建一个目录 ( 例如,在你的主目录下创建 example 目录 ) 。
(2) 打开命令提示符 / 终端窗口并切换到刚才创建的目录。
(3) 使用 npm 创建 package.json 文件,输入:
npm init
然后按回车键。 npm 会问一系列问题,根据实际情况回答对应的问题 ( 或者只按回车键来回答所
有问题 ) 。完成后,它会在你的 example 目录下写入 package.json 文件。
(4) 下一步,安装 Babel( 访问 https://babeljs.io/docs/setup/#installation ,然后单击 CLI 按钮;可在这 个网页上查看是否有更新) 。输入:
npm install --save-dev @babel/core @babel/cli
然后按回车键。 npm 将下载 Babel 、命令行接口及其所有依赖项并将它们安装到示例项目中。 ( 你
可能会收到与 fsevents 模块相关的警告或一些 deprecation 警告,这没有关系。 )
(5) 现在,你可通过直接输入 Babel 来使用它,但是我们可在 package.json 文件中添加一个 npm
脚本命令来简化对它的使用。用你最喜欢的编辑器打开 package.json 文件。如果没有顶层的 script 字 段,请创建一个。( 当前最新版本的 npm 会包含一个有 test 命令的 script 字段,打印一段错误信息。 )
在 script 字段中,添加以下设置:
"build": "babel src -d lib"
现在 package.json 文件的内容应该如代码清单 1-1 所示。在你的文件中, script 字段中可能还有一
1 https://facebook.github.io/jsx/ 。
2 https://reactjs.org/ 。 10 | 深入理解现代 JavaScript
个 test 命令,这没关系。脚本也可能有不同的许可证,我总是将默认值改为 MIT 。最后务必保存该文件。
代码清单 1-1 示例 package.json —— package.json
{
"name": "example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "babel src -d lib"
},
"author": "",
"license": "MIT",
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2"
}
}
(6) Babel 是高度模块化的。尽管我们已经安装了它,但还没有告诉它做任何事情。在此示例中,
我们将使用它的一个预设,通过安装和配置该预设来告诉它将 ES2015 代码转换为 ES5 代码。要安装
这个预设,请键入:
npm install --save-dev babel-preset-env
然后按回车键。在下一步中,我们将对其进行配置。
(7) 现在,需要为 Babel 创建一个配置文件 .babelrc( 注意前面的点号 ) 。使用以下内容创建该文件 ( 或
使用章节下载中的文件 ) :
{
"presets": [
[
"env",
{
"targets": {
"ie": "11"
}
}
]
]
}
该配置告诉 Babel 使用其 env 预设, Babel 文档将其描述为“ . . . a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms . . . are needed by your target environment(s).(……一个智能预设,它允许你使用最新的 JavaScript 特性而不必单独管理需要语法转 换的目标环境……) ”。在这个配置中,如将目标设置为 "ie":"11" ,将告知 env 预设,你的目标环境是 IE11,这适用于下面的示例。在实际使用中,你需要根据自己的情况查看 env 预设 1 的文档或其他预 设或插件的文档。
至此,本示例的 Babel 配置已经完成了。现在创建一些代码进行编译。在 example 目录中创建一
——————————————————————————
1 https://babeljs.io/docs/en/babel-preset-env#docsNav 。
——————————————————————————
个名为 src 的子目录,并在其中创建一个名为 index.js 的文件,其内容如代码清单 1-2 所示。在此过程 的最后,我将向你展示文件树最终的列表,因此,如果你不太确定文件是否创建在正确的目录下,请 不必过于担心。只需要创建文件,如果它的位置不对,将其移到正确的位置即可。
代码清单 1-2 编译 ES2015 示例的输入—— index.js
var obj = {
rex: /\d/,
checkArray: function(array) {
return array.some( entry => this.rex.test(entry) );
}
};
console.log(obj.checkArray(["no", "digits", "in", "this", "array"])); // false
console.log(obj.checkArray(["this", "array", "has", "1", "digit"])); // true
代码清单 1-2 仅使用了 ES2015+ 的一项特性——箭头函数,即 some 函数调用中的 entry =>
this.rex.test (entry) ——上面的代码中加粗显示的部分 ( 是的,这确实是一个函数 ) 。第 3 章将介绍该函数。
如你所见,它通过简短、不完整的形式提供了一种定义函数的简洁方式,并且像封装变量一样对 this 进行了封装( 而不是以调用它们的方式进行 this 设置 ) 。当调用 obj.checkArray(...) 时,即使在 some 回调 方法中,该回调中的 this 变量指的也是 obj 对象,因此 this.rex 指的是 obj 对象的 rex 属性。如果这里 的回调采用的是传统函数,那就不是这样了。
此时, example 目录的内容应如下所示:
example/
+ −− node_modules/
| + −− (various directories and files)
+ −− src/
| + −− index.js
+ −− .babelrc
+ −− package.json
+ −− package-lock.json
准备好进行编译!请输入:
npm run build
然后按回车键。 Babel 将进行它的工作,为你创建 lib 输出目录,并将 ES5 版本的 index.js 写入其
中。最终的 lib / index.js 文件如代码清单 1-3 所示。
代码清单 1-3 编译 ES2015 示例的输出—— index-transpiled-to-es5.js
"use strict";
var obj = {
rex: /\d/,
checkArray: function checkArray(array) {
var _this = this;
return array.some(function (entry) {
return _this.rex.test(entry);
});
}
};
console.log(obj.checkArray(["no", "digits", "in", "this", "array"])); // false
console.log(obj.checkArray(["this", "array", "has", "1", "digit"])); // true
如果将 src / index.js( 代码清单 1-2) 与 lib / index.js( 代码清单 1-3) 进行比较,你会发现其中只有几处
变化 ( 空格除外 ) 。首先, Babel 在编译后的文件顶部添加了 "use strict"; 指令 ( 回想一下,严格模式是 ES5 中添加的一个特性,它修改一些由于各种原因而存在问题的行为) 。这是 Babel 的默认设置,但如果 你的代码依赖于宽松模式,也可将其关闭。
但有趣的地方在于它重写箭头函数的方式。它在 checkArray 中创建了一个名为 _this 的变量,将
其值设置为 this ,然后以传统函数作为 some 函数的回调;在函数中它用 _this 代替 this 。这与前面对箭 头函数的描述相吻合——像封装变量一样对 this 进行了封装。 Babel 只是以 ES5 环境可理解的方式实 现了这一点。
显然,这只是一个很小的示例,但是它说明了如何在旧环境中使用新特性,并让你了解了在项目
中需要这样做时可能使用的一个工具。无论是使用 Gulp 1 、 Grunt 2 、 Webpack 3 、 Browserify 4 、 Rollup 5 ,还是其他任何工具,都可将 Babel 集成到你的构建系统中; https://babeljs.io/docs/setup/#installation 的安装页面提供了所有主要工具的说明。
节选自《深入理解现代JavaScript》一书,想了解更多内容,请点击下方链接
多快好省,购物上京东https://item.m.jd.com/product/13130231.html