美文网首页
ES2020新特性

ES2020新特性

作者: 梁坤同学 | 来源:发表于2020-02-11 20:18 被阅读0次

    可选链 (Optional chaining)

    可选链 让我们在查询具有多层级的对象时,不需要再进行冗余的各种前置校验

    例如日常开发中,我们经常会遇到这种查询

    let name = user && user.info && user.info.name;
    

    又或者是这种

    let age = user && user.info && user.info.getAge && user.info.getAge();
    

    如果在任何级别的对象中都有 undefined 或者 null 的嵌套对象,如果不进行检查,那么很容易命中 Uncaught TypeError: Cannot read property... 这种错误,这很有可能让你的程序崩溃。因此,我们必须检查每个级别,以确保当它遇到 undefined 或 null 对象时不会崩溃。

    使用可选链运算符,只需要使用 ?. 来访问嵌套对象。而且如果碰到 undefined 或 null 属性,那么他只会返回 undefined。

    使用可选链,上面的代码可改为:

    let name = user?.info?.name;
    let age = user?.info?.getAge?.();
    

    可选链中的 ? 表示如果闻号左边的表达式有值,就会继续查询问好后面的字段

    空值合并运算符 (Nullish coalescing Operator)

    undefined 或 null 值所产生的另一个问题,如果我们想要的变量为 undefined 或 null,则必须给变量设置默认值。例如:

    const a = b || '暂无数据';
    

    当使用 || 运算符将 b 赋值给 a 时,如果 b 被定义为 undefined,我们就必须设置一个默认值。
    运算符 || 的问题在于,在 JS 中,所有类似于 0、false 或空字符串之类的值,在进行逻辑操作符判断时,都会自动转化为 false,如果用户输入的本身就是 0,a 也会被赋值为 暂无数据,就会出现逻辑错误。

    为了解决这个问题,创建了 nullish 合并运算符,用 ?? 表示。有了它,我们仅在第一项为 null 或 undefined 时设置默认值。

    使用无效的合并运算符,以上表达式可改为:

    const a = b ?? '暂无数据';
    

    通过 # 给 class 添加私有变量

    class Counter {
        #num = 10;
        increment() {
            this.#num ++;
        }
        getNum() {
            return this.#num;
        }
    }
    const counter = new Counter()
    counter.increment()
    console.log(counter.getNum())   // 11
    console.log(counter.#num)   // SyntaxError
    

    在 ES2020 中,通过 # 可以给 class 添加私有变量。在 class 的外部我们无法获取该值。这样就不需要使用闭包来隐藏不想暴露给外籍的私有变量。

    BigInt

    Js 中 Number 类型只能安全地表示 -(2^53-1)2^53-1 范围内的值,即 Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER, 超出这个范围的整数计算或者表示会丢失精度。

    let num = Number.MIN_SAFE_INTEGER;  // 9007199254740991
    
    num += 1;   // 9007199254740992
    
    // 再加 +1 后无法正常运算
    num += 1;  // 9007199254740992
    
    // 两个不同的值比较,返回 true
    console.log(9007199254740992 === 9007199254740993); // true
    

    为了解决这个问题,ES2020 提供了一种新的数据类型:BigInt
    使用 BigInt 有两种方式:

    1. 在整数字面量后面加 n
      const bigIntNum = 9007199254740993n;
      
    2. 使用 BigInt 函数
      const bigIntNum = BigInt(9007199254740993)
      const anotherBigIntNum = BigInt('9007199254740995')
      
      通过 BigInt,可以安全地进行大数整型计算
      const bigNumRet = 9007199254740993n + 9007199254740993n;
      bigNumRet.toString();   // "18014398509481986"
      

    注意:

    • BigInt 是一种新的数据原始类型
      typeof 9007199254740993n; // 'bigint';
      
    • 尽可能避免通过调用函数 BigInt 方式来实例化超大整型。因为参数的字面量实际也是 Number 类型的一次实例化,超出安全范围的数字,可能会引起精度丢失。

    Promise.allSettled

    Promise.all 缺陷

    Promise.all 具有并发执行异步任务的能力,但是它最大的问题就是如果其中某个任务出现异常(reject),所有任务都会挂掉,Promise 直接进入 reject 状态。

    Promise.all([
        Promise.reject({ code: 500, message: ''服务异常 }),
        Promise.resolve({ code: 200, list: [] }),
        Promise.resolve({ code: 200, list: [] }),
    ]).then(res => {
        // 如果其中一个任务是 reject,则不会执行到这个回调
        RenderContent(res)
    }).catch(error => {
        // 本例中会执行到这个回调
        // error: { code: 500, message: '服务异常' }
    })
    

    我们需要一种机制,如果并发任务中,无论一个任务正常或者异常,都会返回对应的状态(fulfilled 或者 rejected)与结果(业务 value 或者 拒因 reason),在 then 里面通过 filter 来过滤出想要的业务逻辑结果,这就能最大限度的保障业务当前状态的可访问性,而 Promise.allSettled 就是解决这个问题的。

    Promise.allSettled(iterable)

    iterable:一个可迭代的对象,例如 Array,其中每个成员都是 Promise

    返回一个在所有给定的 promise resolved 或者 rejected 的 promise,并带有一个对象数组,每个对象表示对应的 promise 结果。

    Promise.allSettled([
        Promise.reject({ code: 500, message }),
        Promise.resolve({ code: 200, list: [] }),
        Promise.resolve({ code: 200, list: [] }),
    ]).then(res => {
        /*
            [
                { status: "rejected", reason: {...} },
                { status: "fulfilled", value: {...} },
                { status: "fulfilled", value: {...} },
            ]
        */
        // 过滤掉 reject 状态,尽可能多的保证页面区域数据渲染
        RenderContent(res.filter(item => {
            return item.status !== 'rejected';
        }));
    })
    

    dynamic-import

    静态 import 和动态 import() 有各自的特点和使用场景。

    static import 是没有括号的,dynamic import() 是带括号的。

    用法区别:

    // 有声明提升,一般只放在头部位置
    static import: import xxx from 'xxx';
    // 可以放在任何位置
    dynamic import(): const xxx = import('xxx');
    

    按需执行逻辑资源都体现在某一个时间回调中去加载,为了首屏渲染速度更快,很多时候都是按需加载。

    el.onclick = () => {
        import('/example.js').then(module => {
            module.todo();
        }).catch(err => {
            // load error
        })
    }
    

    globalThis

    JavaScript 在不同的环境获取全局对象有不同的方式,node 中通过 global,web 中通过 window、self 等,有些甚至通过 this 获取,但是通过 this 是极其危险的,this 在 js 中很依赖当前的执行上下文。

    globalThis 提供了标准的方式去获取不同环境下的全局对象。它不想 window 或者 self 这些属性,而是确保可以再有无窗口的环境下都可以正常工作,不必担心它的运行环境。

    • 过去获取全局对象的方式,可通过一个全局函数
      const getGlobal = () => {
          if (typeof self !== 'undefined') return self;
          if (typeof window !== 'undefined') return window;
          if(typeof global !== 'undefined') return global;
          throw new Error('unable to locate global object');
      }
      const globals = getGlobal();
      console.log(globals)
      
    • 使用 globalThis 获取全局对象
      console.log(globalThis)
      

    相关文章

      网友评论

          本文标题:ES2020新特性

          本文链接:https://www.haomeiwen.com/subject/bnhffhtx.html