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,那么同样的变化就会反映到其它实例上。
    MapWeakMap 之间的区别在于:对于 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);