ECMAScript 规范史
ECMAScript 基于多种原始技术,最著名的是 JavaScript (Netscape) 和 JScript (Microsoft)。截止2022年,正式标准一共发布12次,es2020草案撰写中。
- 1997年06月,ECMAScript 第一版语言被采纳,标准规范发布;
- 1998年06月,Ecma 大会批准了第二版;
- 1999年12月,强大的正则表达式、更好的字符串处理、新的控制语句、try/catch 异常处理、更严格的错误定义、数字输出格式以及对未来语言增长预期的微小变化被引入标准,第三版发布;
- 第四版并没有完成,没有发布;
- 2009年12月,第五版发布。新增了包括访问器属性、对象的反射创建和检查、属性属性的程序控制、额外的数组操作函数、对 JSON 对象编码格式的支持以及提供增强的错误检查和程序安全性的严格模式等特性;
- 2011年06月,发布了5.1,包含了一些小的修正;
- 2015年06月,ES6正式发布。第六版的完成是之前十五年努力的结晶。包括为大型应用程序、库创建和使用 ECMAScript 作为其他语言的编译目标提供更好的支持。它的一些主要增强包括模块、类声明、词法块范围、迭代器和生成器、异步编程的承诺、解构模式和正确的尾调用。
至此之后,Ecma TC39 采用年度发布节奏
- ES2016,包括对新取幂运算符的支持,并为 Array.prototype 添加了一个名为 includes 的新方法等;
- ES2017,引入了异步函数、共享内存和原子以及较小的语言和库增强、错误修复和编辑更新等;以及对象上的新静态方法:
Object.values
、Object.entries
和Object.getOwnPropertyDescriptors
; - ES2018,通过 AsyncIterator 协议和异步生成器引入了对异步迭代的支持;
- ES2019,引入了一些新的内置函数
Array.prototype
上的flat
和flatMap
用于扁平化数组;Object.fromEntries
用于直接将Object.entries
的返回值转换为新的Object
;String.prototype
上的trimStart
和trimEnd
效果更好;String.prototype.trimLLeft
和trimRight
内置函数的命名替代品。- 允许字符串文字中的
U 2028 (LINE SEPARATOR)
和U 2029 (PARAGRAPH SEPARATOR)
与 JSON 对齐。 - 更新包括要求
Array.prototype.sort
是稳定的排序, - 要求 JSON.stringify 无论输入如何都返回格式良好的 UTF-8,并通过要求它返回相应的原始源文本或标准占位符。
- ES2020,第 11 版引入了
- 字符串的
matchAll
方法,为全局正则表达式生成的所有匹配对象生成迭代器; import()
,一种使用动态说明符异步导入模块的语法;BigInt
,一种用于处理任意精度整数的新数字原语;Promise.allSettled
,一个新的不会短路的 Promise 组合器;globalThis
,一种访问全局 this 值的通用方式;- 专用导出
* as ns from 'module'
语法在模块中使用; - 增加
for-in
枚举顺序的标准化; import.meta
,模块中可用的主机填充对象,可能包含有关模块的上下文信息;- 以及添加两个新的语法功能以改进对“空”值(空或未定义)的处理:空合并,值选择运算符;
- 可选链,一个属性访问和函数调用运算符,如果要访问/调用的值是空的,它就会短路。
- 字符串的
- ES2021,第 12 版引入了
- 用于字符串的
replaceAll
方法; Promise.any
,一个 Promise 组合器,当输入值被满足时短路;AggregateError
,一种新的 Error 类型,用于同时表示多个错误;- 逻辑赋值运算符 (
??=
,&&=
,||=
); WeakRef
,用于引用目标对象而不将其从垃圾收集中保留;FinalizationRegistry
,用于管理在目标对象被垃圾收集时执行的清理操作的注册和注销;- 数字文字的分隔符 (
1_000
); Array.prototype.sort
变得更加精确,减少了导致实现定义的排序顺序的案例数量。
- 用于字符串的
- ES2022,进行ing…
官方地址:ECMAScript® 2022 Language Specification
babel
Babel 是一个工具链,主要用于将采用 ECMAScript 2015 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。概念内容可以参考官网或这里。
Presets
Babel 的预设(preset)可以被看作是一组 Babel 插件或 options
配置的可共享模块。
官方提供的预设
名称 | 说明 |
---|---|
@babel/preset-env | 编译 ES2015 语法 |
@babel/preset-typescript | 编译 Typescript 语法 |
@babel/preset-react | 编译 React 语法 |
@babel/preset-flow | 编译 Flow 语法 |
这里需要说明的是:babel-preset-env 具有不同的版本,包含的规范(插件)也不一致
示例:v7.15.0 包含了 es2020 相关插件;v7.4.0 并不包含 es2020 相关插件。
代码语言:javascript复制{
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
"@babel/plugin-syntax-optional-chaining": "^7.8.3"
}
所以,即便同样指定 babel 的 presets 为 babel-preset-env
,也需要查看其版本,确定指定版本中是否包含相应的新规范内容插件。
presets: [
"@babel/preset-env",
],
name 规范化
默认情况下,Babel 期望插件在其名称中具有 babel-plugin-
或 babel-preset-
前缀。为了避免重复,Babel 有一个名称规范化阶段会在加载项目时自动添加这些前缀。
规则 | 输入 | Normalized |
---|---|---|
绝对路径原封不动地通过 | “/dir/plugin.js” | “/dir/plugin.js” |
以 ./ 开头的相对路径原封不动 | “./dir/plugin.js” | “./dir/plugin.js” |
以 module: 为前缀的标识符都将删除前缀 | “module:foo” | “foo” |
plugin-/preset- 将在任何没有它作为前缀的@babel-scoped 包的开头注入 | “@babel/mod” | “@babel/plugin-mod” |
babel-plugin-/babel-preset- 将作为前缀注入任何没有它作为前缀的无作用域包 | “mod” | “babel-plugin-mod” |
babel-plugin-/babel-preset- 将作为前缀注入任何名称中没有它的@-scoped 包 | “@scope/mod” | “@scope/babel-plugin-mod” |
如果只给出@-scope 名称,babel-plugin/babel-preset 将作为包名称注入 | “@scope” | “@scope/babel-plugin” |
官方地址:https://babeljs.io/docs/en/options#name-normalization
对应es-x版本插件集
示例:es2020
@babel/plugin-proposal-nullish-coalescing-operator @babel/plugin-proposal-optional-chaining @babel/plugin-syntax-import-meta
官方地址:https://babeljs.io/docs/en/plugins-list
vue cli
vue2 中使用 es6 ,需要搞懂 vue cli 同 babel 结合的方式,然后增加相关插件。
一个默认的 Vue CLI 项目会使用 @vue/babel-preset-app(使用的默认 Babel 预设),它通过 @babel/preset-env
和 browserslist
配置来决定项目需要的 polyfill。
代码语言:javascript复制
package.json
文件里的browserslist
字段 (或一个单独的.browserslistrc
文件),指定了项目的目标浏览器的范围。这个值会被 @babel/preset-env 和 Autoprefixer 用来确定需要转译的 JavaScript 特性和需要添加的 CSS 浏览器前缀。
module.exports = {
presets: [
'@vue/app'
]
}
name 规范化:@vue/app
实际对应的是 @vue/babel-preset-app
@vue/babel-preset-app 包括的插件:
代码语言:javascript复制{
"@babel/preset-env": "^7.12.16",
"babel-plugin-dynamic-import-node": "^2.3.3",
"@babel/plugin-proposal-class-properties": "^7.12.13",
"@babel/plugin-proposal-decorators": "^7.12.13",
"@vue/babel-plugin-jsx": "^1.0.3",
"@vue/babel-preset-jsx": "^1.1.2"
}
注意:@vue/babel-preset-app
版本不同,对应的 @babel/preset-env
不同,因此包含的默认规则必然不同。
支持某一特性
以 可选链操作符 ?.
为示例
const obj = {}
obj?.foo?.()
第一步:确定“可选链操作符”为 ES2020 新增特性;
第二步:获取当前工程中 @vue/babel-preset-app
版本,以便获取其依赖项 @babel/preset-env
版本
第三步:根据@babel/preset-env
版本,来确定是否包含 ES2020 特性;
第四步:如果已包含,则工程中可以使用;跳过后续所有步骤;
第五步:如果不包含,或去对应 plugin,列表地址
第六步:项目中按照相关依赖,并增加 plugin 配置
$ pnpm install --save-dev @babel/plugin-proposal-optional-chaining
babel.config.js
代码语言:javascript复制module.exports = {
presets: [
'@vue/app'
],
plugins: [
'@babel/plugin-proposal-optional-chaining'
]
}
template 模板中支持(vue.config.js中增加相关配置)
代码语言:javascript复制chainWebpack: (config) => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.compiler = require('vue-template-babel-compiler')
return options
})
}