ES2021 激动人心的新特性

温馨提示: 阅读此文需有一定的 JavaScript 基础知识,并已了解 ES2020(ES11) 特性

1. 逻辑赋值运算符

逻辑赋值运算符结合逻辑运算符和赋值运算符,它让代码变得简短、让变量和对象属性条件赋值变得简单。ES2021将推出三个新的逻辑操作符,每一个操作符都有两个运算元。

||=  // OR
&&=  // AND
??=  // with
复制代码

逻辑OR ||= 操作符是结合了逻辑 || 操作符和赋值操作符。当前面的值是假值的时候将右边运算元赋值给左边运算元,相当于形式 a || (a = b)

let thirdPlace = 5;
let secondPlace = false;
let firstPlace = null;

thirdPlace  ||= 3;
secondPlace ||= 2;
firstPlace  ||= 1;

console.log(thirdPlace);    // "5"
console.log(secondPlace);   // "2"
console.log(firstPlace);    // "1"
复制代码

同样的,逻辑AND赋值运算符 &&= 结合逻辑&&操作符和赋值操作符,当且仅当运算符左侧的值是真值的时候将运算元右侧的值赋值给运算元左侧,相当于 a && (a = b) 的简写形式。

let thirdPlace = 5;
let secondPlace = false;
let firstPlace = null;

thirdPlace  &&= 3;
secondPlace &&= 2;
firstPlace  &&= 1;

console.log(thirdPlace);    // "5"
console.log(secondPlace);   // "false"
console.log(firstPlace);    // "null"
复制代码

空值赋值操作符 ??=a??(a=b) 的简写形式。当且仅当前面一个值是 null 或者 undefined 的时候将第二个运算元赋值给第一个运算元。

let thirdPlace = 5;
let secondPlace = false;
let firstPlace = null;

thirdPlace  ??= 3;
secondPlace ??= 2;
firstPlace  ??= 1;

console.log(thirdPlace);    // "5"
console.log(secondPlace);   // "false"
console.log(firstPlace);    // "1"
复制代码

当初始化对象属性的时候,这些新操作符非常好用。这些操作符帮助我们保证在 person 对象内部的 firstName 属性在没有赋值的时候已经初始化了 Commander 值。
以前的精简形式:

(() => {
    const person = {
        firstName: 'Unnamed'
    }
    person.firstName || (person.firstName = 'Commander');
    console.log(person.firstName); // "Unnamed"
    person.lastName || (person.lastName = 'Shepard');
    console.log(person.lastName); // "Shepard"
})();
复制代码

ES2021整个结构更加精简:

(() => {
    const person = {
        firstName: 'Unnamed'
    }
    person.firstName ||= 'Commander';
    console.log(person.firstName); // "Unnamed"
    person.lastName ||= 'Shepard';
    console.log(person.lastName); // "Shepard"

})();
复制代码

总结来说,你只是简化了赋值默认值而不是初始化变量。 从:

person.firstName = person.firstName|| person.firstName='Commander';
复制代码

到:

person.firstName ||= 'Commander';
复制代码

注意: 除此之外,采用老的方式实现这种形式,将阻断可能存在的 getter 方法。另一种方式是如果存在 __getter 的话就调用 __getter

2. 字符串替换

当替换一个字符串中所有存在的子序列时,最好的方式是使用正则表达式。你也可以使用 polyfill 的函数 replaceAllPolyfill() ,这个方法对字符串产生一个各自的具体的正则表达式全局搜索。

const winnersPhrase = 'This 111 is the 111 text 111 to gratulate 111 the winners 111 of the 111 race!';

const replaceAllPolyfill = (string, find, replace) => {
    return string.replace(new RegExp(find, 'g'),
        replace);
}

const correctPhrase = replaceAllPolyfill(winnersPhrase, ' 111', '');
console.log(correctPhrase); 
复制代码

另外一种实现形式是采用字符串方法 split(),这个方法以参入的子序列为节点分割字符串为数组,然后再针对这个数组调用 call() 方法,声明新的插入字符串,将所有的子序列合在一起。

const winnersPhrase = 'This 111 is the 111 text 111 to gratulate 111 the winners 111 of the 111 race!';

const replaceAllPolyfill = (string, find, replace) => {
    return string.replace(new RegExp(find, 'g'),
        replace);
}

const correctPhrase = winnersPhrase.split(' 111'). join('');
console.log(correctPhrase);
复制代码

出于性能原因这些方式都是低效的。对于长字符串,频繁的出现字符串搜索。replaceAll() 方法在未来会简化这个流程,它将替换字符串中所有存在的与第一个参数相同的子序列为第二个参数的字符串序列。

const winnersPhrase = 'This 111 is the 111 text 111 to gratulate 111 the winners 111 of the 111 race!';

const correctPhrase = winnersPhrase.replaceAll(' 111', '');
console.log(correctPhrase);
复制代码

3. Promises.any

ES2020已经通过了 PromiseallSettled() 方法。ES2021 Promise 阵营将有一个新的成员,any()。它期望一个 Iterableprmoses,然后返回一个最快 fulfilled 状态的 promise。当所有的 promiserejected 了,any 将返回一个 rejectedpromise

(async () => {
    const promisesToBeResolved = [
        Promise.resolve(555),
        Promise.resolve(666),
        Promise.resolve(777),
    ];
    try {
        const firstResolver = await Promise.any(promisesToBeResolved);
        console.log(firstResolver); // --> 555
    } catch (error) {
        console.error(error);
    }
})();

(async () => {
    const promisesSomeToBeRejected = [
        Promise.reject(555),
        Promise.reject(666),
        Promise.resolve(777),
    ];
    try {
        const firstResolver = await Promise.any(promisesSomeToBeRejected);
        console.log(firstResolver);  // --> 777
    } catch (error) {
        console.error(error);
    }
})();

(async () => {
        const promisesAllToBeRejected = [
            Promise.reject(1),
            Promise.reject(2),
            Promise.reject(5),
        ];
        try {
            const firstResolver = await Promise.any(promisesAllToBeRejected);
            console.log(firstResolver);
        } catch (error) {
           console.error(error);  // All promises were rejected
        }
    }
)();
复制代码

可以看出这个例子,any() 方法等待第一个 resolved 值,而且只会打印 firstResolver,当所有的 promiserejected ,它将在 trycatch 中抛出错误,第三个例子清楚的证明了为什么程序没有打印出 firstResolver

4. 数值分隔符 _

二进制、十六进制和大数终可读

const goldstack1 = 785_00;
const gemstack = 1_000_000_000;
console.log(goldstack1);                // 78500
console.log(gemstack);                  // 1000000000
console.log(goldstack1 === 78500);      // true
console.log(gemstack === 1000000000);   // true
复制代码

我们通过在数字相符的组之间放置分隔符使数字值更加的可读,分隔符适用于十进制表示法的数字以及二进制或十六进制表示法的数字,以及ES2020中引入的 BigInts

注意: 分隔符不会影响===操作符比较两个值

5. Intl.ListFormat

ListFormat 对象的构造方法有两个参数,皆为可选。首个参数是一个语言标识(locale),而第二个参数是一个选项对象 — 包含了 style 和 type 两个属性。

new Intl.ListFormat([locales[, options]])
复制代码

Intl.ListFormat 有一个叫做 format() 的方法,接受一个数组作为参数,并因 locale 和选项而异以相应的方式格式化该参数数组。

以下给出的是一些结合了不同 locale 和选项的例子。

const arr = ['Pen', 'Pencil', 'Paper']
 
let obj = new Intl.ListFormat('en', { style: 'short', type: 'conjunction' })
console.log(obj.format(arr)) 
 
/****  输出  ****/
// Pen, Pencil, & Paper
 
 
obj = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' })
console.log(obj.format(arr)) 
 
/****  输出  ****/
// Pen, Pencil, and Paper
 
 
obj = new Intl.ListFormat('en', { style: 'narrow', type: 'conjunction' })
console.log(obj.format(arr)) 
 
/****  输出  ****/
// Pen, Pencil, Paper
 
 
// 传入意大利语标识
obj = new Intl.ListFormat('it', { style: 'short', type: 'conjunction' })
console.log(obj.format(arr)) 
 
/****  输出  ****/
// Pen, Pencil e Paper
 
 
// 传入德语标识
obj = new Intl.ListFormat('de', { style: 'long', type: 'conjunction' })
console.log(obj.format(arr)) 
 
/****  输出  ****/
// Pen, Pencil und Paper
复制代码

6. Intl.DateTimeFormat 的 dateStyle 和 timeStyle 选项

Intl.DateTimeFormat 对象是一个支持语言敏感日期和时间格式化的构造器。拟议的 dateStyle 和 timeStyle 选项可被用于获取一个 locale 特有的日期和给定长度的时间。

一些不同选项和语言(locale)的例子展示在此:

// 短格式的时间
let o = new Intl.DateTimeFormat('en' , { timeStyle: 'short' })
console.log(o.format(Date.now()))
// 11:27 PM
 
 
// 中等格式的时间
o = new Intl.DateTimeFormat('en' , { timeStyle: 'medium'})
console.log(o.format(Date.now()))
// 11:27:57 PM
 
 
// 长格式的时间
o = new Intl.DateTimeFormat('en' , { timeStyle: 'long' })
console.log(o.format(Date.now()))
// 11:27:57 PM GMT+11
 
 
// 短格式的日期
o = new Intl.DateTimeFormat('en' , { dateStyle: 'short'})
console.log(o.format(Date.now()))
// 10/6/20
 
 
// 中等格式的日期
o = new Intl.DateTimeFormat('en' , { dateStyle: 'medium'})
console.log(o.format(Date.now()))
// Oct 6, 2020
 
 
// 长格式的日期
o = new Intl.DateTimeFormat('en' , { dateStyle: 'long'})
console.log(o.format(Date.now()))
// October 6, 2020
复制代码

dateStyle 和 timeStyle 选项共用并结合不同语言标识的例子,如下所示:

let abc
 
// 英语
abc = new Intl.DateTimeFormat('en' , { timeStyle: 'short', dateStyle: 'long'})
console.log(abc.format(Date.now()))
// October 6, 2020 at 11:40 PM
 
 
// 意大利语
abc = new Intl.DateTimeFormat('it' , { timeStyle: 'short', dateStyle: 'long'})
console.log(abc.format(Date.now()))
// 6 ottobre 2020 23:40
 
 
// 德语
abc = new Intl.DateTimeFormat('de' , { timeStyle: 'short', dateStyle: 'long'})
console.log(abc.format(Date.now()))
// 6. Oktober 2020 um 23:40
复制代码

先记录这些,本文会持续更新,作为一个开发者,追踪一门语言的新特性很重要。
如果这篇笔记对你有所帮助,感谢点一颗小心心,您的支持是我继续创作的动力!

参考文献:

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享