1. 简介
ECMAScript 2020,简称 ES2020 或 ES11,是 JavaScript 语言的一个新版本,于 2020 年 6 月发布。工作小组在这个版本中引入了几个新的特性和改进。本文将对这些新功能进行详细介绍,并提供相关示例代码和指导意义。
2. 新特性
2.1 可选链运算符(Optional Chaining Operator)
可选链运算符是一种简化嵌套属性访问的语法。在访问对象的某个属性时,如果该属性不存在,一般需要使用 if 判断,或采用多层短路运算符(&&)连接的方式,才能避免出现 TypeError 错误。例如:
if (obj && obj.prop && obj.prop.subprop) { // do something } 或 const subprop = obj && obj.prop && obj.prop.subprop;
使用可选链运算符,则可以使这种操作更加简洁。例如:
const subprop = obj?.prop?.subprop;
如果 obj 或者 prop 不存在,返回值为 undefined,不会抛出 TypeError 错误。可选链运算符还可以与函数调用和数组下标访问相结合。例如:
const len = arr?.length ?? 0; const result = obj?.method?.(param);
其中,?? 表示空值合并运算符,它的作用是指定在左侧操作数为空 (null 或 undefined) 的情况下,使用它右侧的默认值。
2.2 空值合并运算符(Nullish Coalescing Operator)
在以前的版本中,|| 运算符被广泛用于提供默认值的场景。然而,|| 运算符有一个弊端,它会将 falsy 值(false、0、null、undefined、NaN、"" 等)都视为“空值”,而不仅仅是 null 或 undefined。这可能导致一些副作用,例如对于普通的数字 0,|| 运算符会返回默认值,这显然是不合理的。在 ES2020 中,添加了一个新的运算符 ??,与 || 运算符类似,但只有在左侧的操作数为 null 或 undefined 时才会返回右侧的默认值。例如:
const result = x ?? y;
当 x 为 null 或 undefined 时,返回 y 的值,否则返回 x 的值。
2.3 动态 import()
以前,使用 import 语句导入模块时,只能使用静态模块路径,即在编译时就确定的路径。而动态导入 (Dynamic import) 允许在运行时根据需要加载模块,以更加灵活地管理模块的加载。在 ES2020 中,添加了动态 import() 函数,它的语法类似于普通函数调用:
import { foo } from './foo.js'; async function loadModule() { const { bar } = await import('./bar.js'); console.log(foo, bar); }
动态 import() 方法将返回一个 promise,它会异步加载模块并返回模块的 namespace 对象。可以使用 await 关键字等待该 promise 执行完毕。注意:动态 import() 方法只能作为模块内的顶级 await 表达式中的一部分使用。
2.4 globalThis 对象
在 Web 开发中,我们经常需要使用顶级对象 (global object) 来访问全局变量和函数。不同的 JavaScript 环境有不同的顶级对象,例如浏览器中的 window 对象、Node.js 中的 global 对象等。为了简化该过程并避免平台差异,ES2020 中引入了一个新的全局对象 globalThis,它始终指向全局作用域下的 this 关键字,可以用于在任何运行时环境下访问全局对象。例如:
console.log(globalThis);
2.5 BigInt 类型
在 JavaScript 中,如果使用 Number 类型来表示数字,最大值约为 2^53-1,而超过这个范围的数字会丢失精度。为了解决这个问题,ES2020 中引入了一个新的原始数据类型 BigInt,可以用于存储任意精度的整数。在 ES2020 中,可以通过后缀 n 指定一个 BigInt,例如:
const n = 9007199254740993n; console.log(n); // 9007199254740993n
值得注意的是,BigInt 类型不能与普通数字混合运算。
3. 改进
除了上述新特性之外,ES2020 中还对一些现有功能进行了改进,以提高代码质量和开发效率。
3.1 Promise.allSettled()
在以前的版本中,Promise.all() 方法用于等待多个 promise 对象全部完成,并返回所有 promise 的结果。如果有一个 promise 被拒绝,Promise.all() 方法会立即返回错误。在 ES2020 中,引入了一个新的方法 Promise.allSettled(),它的作用类似于 Promise.all(),但不会因为某个 promise 被拒绝而立即返回错误,而是返回所有 promise 的状态和结果,即使其中一些 promise 被拒绝。例如:
Promise.allSettled([ Promise.resolve(1), Promise.reject(new Error('error')), Promise.resolve(2) ]).then(results => { console.log(results); });
输出结果为:
[ {status: "fulfilled", value: 1}, {status: "rejected", reason: Error: error}, {status: "fulfilled", value: 2} ]
3.2 String.prototype.matchAll()
在以前的版本中,String.prototype.match() 方法用于查找一个字符串中的所有匹配项,并返回一个数组。但是,这个方法只返回第一个匹配项及其相关信息,如果要查找所有匹配项,则需要结合正则表达式以及循环等方式来实现。在 ES2020 中,引入了一个新的方法 String.prototype.matchAll(),它可以一次性查找所有匹配项,并返回一个迭代器。例如:
const str = 'hello world'; const pattern = /[a-z]/g; for (const match of str.matchAll(pattern)) { console.log(match); }
输出结果为:
["h", index: 0, input: "hello world"] ["e", index: 1, input: "hello world"] ["l", index: 2, input: "hello world"] ["l", index: 3, input: "hello world"] ["o", index: 4, input: "hello world"] ["w", index: 6, input: "hello world"] ["o", index: 7, input: "hello world"] ["r", index: 8, input: "hello world"] ["l", index: 9, input: "hello world"] ["d", index: 10, input: "hello world"]
该方法也可以接受一个正则表达式字符串作为参数,但是需要使用 new RegExp() 构造函数来初始化正则表达式,例如:
const str = 'hello world'; const pattern = new RegExp('[a-z]', 'g'); for (const match of str.matchAll(pattern)) { console.log(match); }
3.3 其他改进
- import.meta 属性:用于访问模块的元数据,例如模块的 URL。
- Function.prototype.toString() 保留空格:在 ES2020 中,Function.prototype.toString() 方法将保留函数体中的所有空格和注释。
- for-in 循环的性能改进:在 ES2020 中,对 for-in 循环进行了优化,对于非数组类型的对象,for-in 循环的性能大幅提升。
4. 学习和指导意义
ES2020 是 JavaScript 语言的一个重要版本,引入了许多新的特性和改进。这些新功能涉及到语法、API、性能等方面,都有助于提高代码的可读性、可维护性、性能和可靠性。掌握和应用这些新功能,可以使我们更加高效地编写代码,减少开发调试时间和代码错误率。
在中大型团队和项目中,使用新版本的 JavaScript 语言和相关工具,例如 TypeScript、Babel 等,可以提高代码的规范化程度,减少代码错误和维护成本,同时也增加了团队协作和代码复用的可行性。
总之,在学习和使用 ES2020 的过程中,我们应该不断地进行实践和总结,以便更好地应对未来的项目需求和变化。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a47ab6add4f0e0ffcc26f6