美文网首页
es2020新特性

es2020新特性

作者: 夜雨声烦人 | 来源:发表于2020-05-02 11:55 被阅读0次

    文章来源:方凳雅集

    前言
    自从ES6发布之后,TC39这个负责开发ECMAScript标准的机构每年都会发布新特性。

    新功能概览
    Optional Chaining
    Nullish coalescing Operator
    globalThis
    Promise.allSettled
    String.prototype.matchAll
    BigInt
    for-in mechanics
    import()

    详细介绍

    可选链运算符 - 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];
    

    空值合并运算符 - Nullish coalescing Operator

    获取对象的属性的时候,我们经常需要为 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

    在不同环境下是很难轻便的获取全局对象的。因为,在浏览器侧,全局对象可能是 window 或者 self 或者 this 或者 frames;在 node,全局对象可以从 global 或者 this 获取;在非严格模式下,方法里面的 this 指向全局对象,但是在严格模式下又是 undefined ;当然,我们也可以通过 Function('return this')() 获取全局对象,但是在某些CSP设置下的浏览器中又不能访问,例如Chrome Apps。这些问题就导致我们可以通过如下代码:

    var getGlobal = function () {
        // the only reliable means to get the global object is
        // `Function('return this')()`
        // However, this causes CSP violations in Chrome apps.
        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');
    };
    

    所以我们需要一个标准的方式去获取不同环境下的全局对象:globalThis。例如:

    function canMakeHTTPRequest() {
        return typeof globalThis.XMLHttpRequest === 'function';
    }
    console.log(canMakeHTTPRequest());
    // expected output (in a browser): true
    

    Promise.allSettled

    相信大家都知道,Promise.all 是可以并发执行多个任务的,但是 Promise.all 有个缺陷,那就是只要其中有一个任务失败了,就会直接进入 catch 的流程,想象一下,我们有两个请求,一个失败了,结果都挂了,这不是我们想要的。

    const promise1 = new Promise((resolve) => setTimeout(resolve, 200, 'good'));
    const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'reject'));
    const promises = [promise1, promise2];
    Promise.all(promises).
    then((ret)=>{
      // 不会触发
      debugger
    })
      .catch((ret)=>{
      console.log(ret); // reject
    })
      .finally(()=>{
      // 会触发,获取不到我们想要的内容
    });
    

    我们需要一个方法来保证如果一个任务失败了,其它任务还会继续执行,这样才能最大限度的保障业务的可用性
    。这时候Promise.allSettled 出现了,Promise.allSettled 会返回一个 promise,这个返回的 promise 会在所有的输入的 promise resolve 或者 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)));
    // expected output:
    // {status: "fulfilled", value: 3}
    // {status: "rejected", reason: "foo"}
    

    String.prototype.matchAll

    matchAll 的行为跟 match 有点像,但 matchAll 返回的是一个迭代器,通过这个迭代器我们可以快速的获取匹配的所有内容。
    在了解matchAll之前先来看看 match 有什么问题。首先我们先来看一下代码:

    const regex = /t(e)(st(\d?))/g;
    const string = 'test1test2';
    const results = string.match(regex);
    console.log(results);
    // → ['test1', 'test2']
    

    执行完之后可以发现,匹配到的内容是 test1,test2。而把正则的全局匹配选项去掉之后,得到的内容却是:

    ['test1', 'e', 'st1', '2', index: 0, input: 'test1test2', groups: undefined]
    

    如果需要 test2 相关的匹配,这时候就没有了,那么怎么获取到 test2 相关的匹配?在此之前,我们可以使用 replace ,当然,代码长了点:

    var regex = /t(e)(st(\d?))/g;
    var string = 'test1test2';
    var matches = [];
    string.replace(regex, function () {
        var match = Array.prototype.slice.call(arguments, 0, -2);
        match.input = arguments[arguments.length - 1];
        match.index = arguments[arguments.length - 2];
        matches.push(match);
        // example: ['test1', 'e', 'st1', '1'] with properties `index` and `input`
    });
    matches;
    // ["test1", "e", "st1", "1", input: "test1test2", index: 0]
    // ["test2", "e", "st2", "2", input: "test1test2", index: 5]
    

    为了简化上面又臭又长的代码,于是乎就有了 matchAll

    let regexp = /t(e)(st(\d?))/g;
    let str = 'test1test2';
    let array = [...str.matchAll(regexp)];
    console.log(array[0]);
    // expected output: Array ["test1", "e", "st1", "1"]
    console.log(array[1]);
    // expected output: Array ["test2", "e", "st2", "2"]
    

    BigInt

    BigInt 是一种内置对象,它提供了一种方法来表示大于 253 - 1 的整数。这原本是 Javascript 中可以用 Number 表示的最大数字。
    相关语法如下,我们可以通过在数字后面添加n或者通过 BigInt() 来创建 BigInt 变量。

    const theBiggestInt = 9007199254740991n;
    const alsoHuge = BigInt(9007199254740991);
    // 9007199254740991n
    typeof alsoHuge === 'bigint' // true
    bigint 跟 number 一样,也支持+,*,-,**和%等运算符:
    const previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER);
    // ↪ 9007199254740991
    const maxPlusOne = previousMaxSafe + 1n;
    // ↪ 9007199254740992n
     
    const theFuture = previousMaxSafe + 2n;
    // ↪ 9007199254740993n, this works now!
    const multi = previousMaxSafe * 2n;
    // ↪ 18014398509481982n
    const subtr = multi – 10n;
    // ↪ 18014398509481972n
    const mod = multi % 10n;
    // ↪ 2n
    const bigN = 2n ** 54n;
    // ↪ 18014398509481984n
    bigN * -1n
    // ↪ –18014398509481984n
    bigint 可以像平时一样跟 number 比较大小:
    1n < 2
    // ↪ true
    2n > 1
    // ↪ true
    2 > 2
    // ↪ false
    2n > 2
    // ↪ false
    2n >= 2
    // ↪ true
    

    转换成布尔类型的时候,bigint 的行为跟 number 是一样的:

    if (0n) {
      console.log('Hello from the if!');
    } else {
      console.log('Hello from the else!');
    }
    // ↪ "Hello from the else!"
    0n || 12n
    // ↪ 12n
    0n && 12n
    // ↪ 0n
    Boolean(0n)
    // ↪ false
    Boolean(12n)
    // ↪ true
    !12n
    // ↪ false
    !0n
    

    bigint 可以像 number 那样转换成字符串的

    1n + '2'
    // ↪ "12"
    '2' + 1n
    // ↪ "21"
    需要注意的点
    bigint 跟 number不严格相等
    0n === 0
    // ↪ false
    0n == 0
    // ↪ true
    

    bigint 不能跟 number一起运算

    1n + 2
    // ↪ TypeError: Cannot mix BigInt and other types, use explicit conversions
    1n * 2
    // ↪ TypeError: Cannot mix BigInt and other types, use explicit conversions
    不能使用+把bigint转换成number
    +1n
    // ↪ TypeError: Cannot convert a BigInt value to a number
    Number(1n)
    // ↪ 1
    

    for-in mechanics

    以前在不同的引擎下for in循环出来的内容顺序是可能不一样的,现在标准化了。
    异步加载模块 - import()
    有时候我们需要动态加载一些模块,这时候就可以使用 import() 了

    // logger.js
    export default {
        log: function() {
            console.log(...arguments);
        }
    };
    import('./logger.js')
      .then((module)=>{
      module.default.log('p9');
    })
    

    当然,也可以使用await进行等待

    let module = await import('/modules/my-module.js');
    

    后记
    授人以鱼不如授人以渔,以后要看ES的新特性,可以查看GitHub上的文档。

    参考资料
    MDN
    https://github.com/tc39/proposals/blob/master/finished-proposals.md
    https://developers.google.com/web/updates/2019/02/string-matchall
    https://blog.logrocket.com/5-es2019-features-you-can-use-today/

    相关文章

      网友评论

          本文标题:es2020新特性

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