ES2020 新增语法
-
Parcel bundler
由于许多人的浏览器版本低,我们需要使用 babel 来让用户使用无法使用的特性。为了简单起见,我将使用 Parcel bundler 使一切尽快运行。$ yarn add parcel-bundler
"scripts": { "start": "parcel index.html" },
具体环境安装参考ES6 环境搭建
-
私有变量
通过在对象属性前面加 #,就可以实现对象属性私有,外界直接访问会报错。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
你可以创建模块,而模块中的所有东西都是私有的,直到以及除非你使用 exports 公开它。let private1 = new WeakMap(); let private2 = new WeakMap(); class MyClass { constructor() { this.setPrivate1("something"); private2.set(this, "something else"); } getPrivate1() { return private1.get(this); //"something" } getPrivate2() { return private2.get(this); //"something else" } setPrivate1(val) { private1.set(this, val); } } module.exports = MyClass;
为什么我们不声明一个变量 private1,然后将它所需的值赋给它呢?原因是,变量 private1 是一个会在 MyClass 的所有实例中共享的单一变量。所以只要有任何一个实例修改了 private1,那么同样的变化就会反映到其它实例上。Map 和 WeakMap 之间的区别在于:对于 WeakMap 来说,如果键对象准备好被垃圾回收,就会自动删除值;而对于 Map 来说,它会一直维持一个对键对象的引用,从而会导致内存泄漏。
-
Promise.allSettled
该 Promise.allSettled() 方法返回一个在所有给定的 promise 都已经 fulfilled 或 rejected 后的 promise,并带有一个对象数组,每个对象表示对应的 promise 结果。当您有多个彼此不依赖的异步任务成功完成时,或者您总是想知道每个 promise 的结果时,通常使用它。相比之下,Promise.all() 更适合彼此相互依赖或者在其中任何一个 reject 时立即结束。const promise1 = Promise.resolve(3); const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo')); const promises = [promise1, promise2]; Promise.allSettled(promises). then((results) => results.forEach((result) => console.log(result.status))); // expected output: // "fulfilled" // "rejected"
一旦所指定的 promises 集合中每一个 promise 已经完成,无论是成功的达成或被拒绝,未决议的 Promise 将被异步完成。那时,所返回的 promise 的处理器将传入一个数组作为输入,该数组包含原始 promises 集中每个 promise 的结果。对于每个结果对象,都有一个 status 字符串。如果它的值为 fulfilled,则结果对象上存在一个 value 。如果值为 rejected,则存在一个 reason 。value(或 reason )反映了每个 promise 决议(或拒绝)的值。更多的 promise API
-
合并空运算符(??)
由于JavaScript是动态类型的,因此在分配变量时,您需要牢记JavaScript对真实/错误值的处理。如果我们有一个带有某些值的对象,有时我们希望允许使用从技术上讲是虚假的值,例如空字符串或数字0。设置默认值很快会令人讨厌,因为默认值会覆盖应为有效值的值。let person = { profile: { name: "", age: 0 } }; console.log(person.profile.name || "Anonymous"); // Anonymous console.log(person.profile.age || 18); // 18
我们可以使用 ?? 操作符来代替 ||,使其类型更严格一些,这只允许在值为 null 或 undefined 时使用默认值。console.log(person.profile.name ?? "Anonymous"); // "" console.log(person.profile.age ?? 18); // 0
-
可选链式操作符(?.)
与合并空操作符类似,JavaScript 在处理错误值时可能无法按我们希望的方式工作。如果我们想要的是未定义的,我们可以返回一个值,但是如果到它的路径是未定义的呢 ? 通过在 . 之前添加一个问号,我们可以使值的路径的任何部分成为可选的,这样我们仍然可以与它交互。let person = {}; console.log(person.profile.name ?? "Anonymous"); // person.profile is undefined console.log(person ?. profile ?. name ?? "Anonymous"); console.log(person ?. profile ?. age ?? 18);
-
BigInt
JavaScript 可以处理的最大安全整数是 (2^53 - 1),我们可以在 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放在末尾,我们可以与大得离谱的数字进行交互。我们无法将标准数字与 BigInt 数字混合在一起,因此任何数学运算都需要使用 BigInt 来完成。const bigNum = 100000000000000000000000000000n; console.log(bigNum * 2n); // 200000000000000000000000000000n
-
动态引入(Dynamic Import)
如果你有一个工具函数文件,其中一些函数可能很少被使用,将他们完整导入可能只是浪费资源。现在我们可以使用 async/await 来动态地导入我们需要的依赖项。// math.js const add = (num1, num2) => num1 + num2; export { add };
// index.js const doMath = async (num1, num2) => { if (num1 && num2) { const math = await import('./math.js'); console.log(math.add(5, 10)); }; }; doMath(4, 2);