es2020

155 阅读4分钟
安装

由于许多人的浏览器版本低,我们需要使用babel来让用户使用无法使用的特性。为了简单起见,我将使用Parcel bundler使一切尽快运行。

$ yarn add parcel-bundler
"scripts": {
  "start": "parcel index.html"
},

不幸的是,现在似乎还没有ES2020的有效预设。 如果将它们放在.babelrc文件中并保存,Parcel应该会为您安装所有内容

{
  "plugins": [
    "@babel/plugin-proposal-nullish-coalescing-operator",
    "@babel/plugin-proposal-optional-chaining",
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-proposal-private-methods",
    "@babel/plugin-syntax-bigint"
  ]
}
  1. 可选链运算符 - Optional Chaining

    有时候为了访问深层嵌套的属性,我们需要写一个很长的&&链去检查每个属性是否存在,代码如下:

    var price = result && result.body && result.body.data && result.body.data.price;
    

    事实上在日常开发中我们经常要这么做,而且如果我们不这么做,那么很可能导致程序异常。为了简化上述的代码,于是乎新增了可选链运算符,代码如下

    var price = result?.body?.data?.price;
    

    可选运算符不仅能作用到属性上,也能作用到方法。

    const result = {}; 
    const price = result?.body?.data?.price;  
    
    const user = {}; 
    const name = user?.getInfo?.().getName?.();  
    
    const respone = {}; 
    const firstProduct = respone?.body?.data?.products?.[0];
    
  2. 空值合并运算符 - Nullish coalesceing oprator

    获取对象的属性的时候,我们经常需要为 null/undefined 的属性设置默认值。目前正常的情况下我们可以使用 || 运算符,例如:

    var user = {}; 
    var name = user.name || 'p9';
    

    但是,这么做会导致false,0,空字符串等属性会被覆盖掉,这是我们不愿意看到的,这时候就可以使用空值合并运算符来避免。例如:

    const response = {
      settings: {
        nullValue: null,
        height: 400,
        animationDuration: 0,
        headerText: '',
        showSplashScreen: false
      }
    };
    
    const undefinedValue = response.settings.undefinedValue ?? 'some other default'; 
    // result: 'some other default'
    
    const nullValue = response.settings.nullValue ?? 'some other default'; 
    // result: 'some other default'
    
    const headerText = response.settings.headerText ?? 'Hello, world!'; 
    // result: ''
    
    const animationDuration = response.settings.animationDuration ?? 300; 
    // result: 0
    
    const showSplashScreen = response.settings.showSplashScreen ?? true; 
    // result: false标准化的全局对象 - globalThis
    
  3. 动态引入 import()

    如果您有一个写满实用程序功能的文件,而且其中某些功能可能很少使用,那么导入其所有依赖项可能只是浪费资源。 现在,我们可以使用async / await在需要时动态导入依赖项。

    (async () => {
      if (process.env.NODE_ENV === 'development') {
        // 动态加载Vconsole
        const { default: VConsole } = await import('vconsole');
        new VConsole();
      }
    })()
    
  4. BigInt

    avaScript可以处理的最大安全整数是(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
    
  5. Promise.allSettled

    当我们处理多个Promise时,特别是当它们相互依赖时,记录每个Promise所发生的事情来调试错误是很有必要的。通过Promise.allSettled,我们可以创建一个新的Promise,它只在所有传递给它的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}
    // ]
    
  6. 私有属性

    类的主要目的之一是将代码包含到更可重用的模块中。因为你将创建一个在许多不同地方使用的类,所以你可能不希望它内部的所有内容都是全局可用的。现在,通过在属性或方法前面添加一个简单的哈希符号,我们可以将它们完全保留为类内部使用.

    class Message {
     #message = "Howdy" // 相当于ts里的 private
    
     greet() { console.log(this.#message) }
    }
    
    const greeting = new Message()
    
    greeting.greet() // Howdy
    console.log(greeting.#message) // Private name #message is not defined