ES2020新特性

可选链 (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)
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • [TOC] 参考阮一峰的ECMAScript 6 入门参考深入浅出ES6 let和const let和const都...
    郭子web阅读 1,771评论 0 1
  • 第一章:块级作用域绑定 块级声明 1.var声明及变量提升机制:在函数作用域或者全局作用域中通过关键字var声明的...
    BeADre_wang阅读 816评论 0 0
  • https://kangax.github.io/compat-table/es6/ 查询各个浏览器对ES的支持:...
    肉桂猿阅读 159评论 0 1
  • 语句 JavaScript程序的执行单位为行(line),也就是一行一行地执行。一般情况下,每一行就是一个语句。 ...
    米塔塔阅读 452评论 1 10
  • JavaScript语言精粹 前言 约定:=> 表示参考相关文章或书籍; JS是JavaScript的缩写。 本书...
    微笑的AK47阅读 576评论 0 3