JavaScript 是一门不断迭代、快速发展的语言,自 2015 年 ES2015(ES6)面世以来,许多新特性将以前所未有的速度被整合到现代浏览器和其他 JavaScript 运行时引擎(例如 Node.js)中。在本文中,我们将看一看 ES2020(ES10) 新增的一些最新和最出色的特性。
由于有相当多的用户不会主动去升级他们的浏览器,为了能在旧版本浏览器中运行这些新特性,我们使用 Babel 编译器来进行转码。这里我们使用的是 parcel-bundler
编译器。
Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。
yarn add parcel-bundler
1. Private Class Variables(类的私有字段)
类的主要目的之一是将我们的代码编写更多可重用的模块,当你创建一个在许多不同地方使用的类时,你可不想让它的一些私有变量暴露出来。
这时候,我们通过在变量或函数前面添加一个简单的哈希符号 #
,将它们定义为私有变量完全保留给类内部使用,这样就不需要使用闭包来隐藏不想暴露给外界的私有变量了。
class Message {
#message = "Howdy"
greet() { console.log(this.#message) }
}
const greeting = new Message()
greeting.greet() // Howdy
console.log(greeting.#message) // Private name #message is not defined
2. Promise.allSettled
我们知道 Promise.all 具有并发执行异步任务的能力。但是,如果参数中的任何一个 promise 返回 reject,那么整个 Promise.all 调用会立刻停止,并返回一个 reject 的新 Promise 对象。
Promise.allSettled 跟 Promise.all 类似, 不同之处在于,它不会进行短路,也就是说当 Promise 全部处理完成后,我们可以拿到每个 Promise 的状态,而不管是否处理成功。查看下面代码,首先创建 2 个新的 Promise,使用 Promise.allSettled 方法执行,当传递给它的所有 Promise 都完成时,返回了一个数组,其中包含了每个 Promise 的状态数据。
const p1 = new Promise((res, rej) => setTimeout(res, 1000));
const p2 = new Promise((res, rej) => setTimeout(rej, 1000));
Promise.allSettled([p1, p2]).then(data => console.log(data));
// [
// Object { status: "fulfilled", value: undefined},
// Object { status: "rejected", reason: undefined}
// ]
3. Nullish Coalescing Operator(空位合并运算符)
因为 JavaScript 是动态类型,在定义变量时,需要牢记 JavaScript 对 true/false 值的处理。假设有一个对象,这时我们希望允许使用伪值,例如“空字符串“或“0”。这时候,利用||
运算符设置默认值会产生相反的效果,因为默认值会覆盖原来有效的值。我们来看看下面代码会更加清晰明了:
let person = {
profile: {
name: "",
age: 0
}
};
console.log(person.profile.name || "Anonymous"); // 此处想要输出的是 空字符,而非 Anonymous
console.log(person.profile.age || 18); // 此处想要输出的是 0,而非 18
这时,我们就可以使用 ES2020 的新特性:空位合并运算符 ??
来处理上面这个情况:
console.log(person.profile.name ?? "Anonymous"); // ""
console.log(person.profile.age ?? 18); // 0
4. Optional Chaining Operator(可选链运算符)
可选链运算符可以让我们在查询具有多个层级的对象时,不再需要进行冗余的各种前置校验。代码解释一切:
const articleData = await (
await fetch('https://api/articles.json')
).json()
// 可选链调用
const nullIsCool = articleData.articles[0]?._next?.layout;
// 请不要让我再用这样的写法
const thisIsNasty = articleData.articles[0] &&
articleData.articles[0]._next &&
articleData.articles[0]._next.title;
可以看出,有了可选链运算符,只需要使用 ?.
来访问嵌套对象,可以大量简化繁琐的前置校验操作,代码更安全,更清爽。
5. BigInt(大整型)
Javascript 可以处理的最大数字是 2^53,我们可以查看 MAX_SAFE_INTEGER
const max = Number.MAX_SAFE_INTEGER;
console.log(max); // 9007199254740991
超出这个范围的整数计算就会变得很奇怪。
console.log(max + 1); // 9007199254740992
console.log(max + 2); // 9007199254740992
console.log(max + 3); // 9007199254740994
console.log(Math.pow(2, 53) == Math.pow(2, 53) + 1); // true
我们可以使用新的 BigInt 数据类型解决此问题,通过在末尾加上字母n
,我们可以开始使用大数字并进行计算交互。
const bigNum = 100000000000000000000000000000n;
console.log(bigNum * 2n); // 200000000000000000000000000000n
6. Dynamic Import(动态引入)
如果你有一个功能很完善的功能模块文件,但其中某些功能可能很少使用,导入这些所有依赖项可能会浪费很多时间。现在,我们可以使用 async / await
在需要时才动态导入这些依赖项。
// math.js
const add = (num1, num2) => num1 + num2;
export { add };
const doMath = async (num1, num2) => {
if (num1 && num2) {
const math = await import('./math.js');
console.log(math.add(5, 10));
};
};
doMath(4, 2);
参考
- https://juejin.im/post/5e1bcaa1f265da3e140fa3ee#heading-8
- https://alligator.io/js/es2020/