ES7 至 ES12 实用的新语法

2023-12-22 14:34:55

在这里插入图片描述

ES7 至 ES12 实用的新语法

es2016之后有很多很实用的新特性,其中有很多也已经用上了,本次分享想做一个新特性的汇总,希望能对大家有一定的帮助。
以下的特性顺序并不是按照时间顺序来的,为了方便记忆,按照数据类型和语法类型做了归类。
每个新特性会按照概念,语法和示例几个方面来介绍。

String 方法的扩展
String.prototype.{padStart/padEnd}
String.prototype.{trimStart,trimEnd}
String.prototype.replaceAll
String.prototype.matchAll
Array方法的扩展
Array.prototype.includes()
Array.prototype.flat()
Array.prototype.flatMap()
Array.prototype.at
Object方法的扩展
Object.values()
Object.entries()
Object. fromEntries
Object.getOwnPropertyDescriptors()
Object.prototype.hasOwn
promise
Promise.prototype.finally()
Promise.allSettled()
Promise.any
表达式和运算符
求幂 (**)
可选链操作符 ?.
空值合并运算符 ??
逻辑与赋值 &&=
逻辑或赋值 ||=
逻辑空赋值??=
globalThis
BigInt
for await of
Error Cause

String 方法的扩展

String.prototype.{padStart/padEnd}

padStart() 方法用另一个字符串填充当前字符串(如果需要的话,会重复多次),以便产生的字符串达到给定的?度。从当前字符串的左
侧开始填充。
padEnd() 方法会用一个字符串填充当前字符串(如果需要的话则重复填充),返回填充后达到指定?度的字符串。从当前字符串的末
尾(右侧)开始填充。
语法

1 str.padStart(targetLength [, padString])
参数
targetLength:当前字符串需要填充到的目标?度。如果这个数值小于当前字符串的?度,则返回当前字符串本身。
padString:可选的。填充字符串。如果字符串太?,使填充后的字符串?度超过了目标?度,则只保留最左侧的部分,其他部
分会被截断。此参数的默认值为 " "(U+0020)。
语法

1 str.padEnd(targetLength [, padString])
参数
targetLength:当前字符串需要填充到的目标?度。如果这个数值小于当前字符串的?度,则返回当前字符串本身。
padString:可选的。填充字符串。如果字符串太?,使填充后的字符串?度超过了目标?度,则只保留最左侧的部分,其他部
分会被截断。此参数的缺省值为 " "(U+0020)
示例

1 'abc'.padStart( 5 ); // " abc"
2 'abc'.padStart( 10 , "foo"); // "foofoofabc"
3 'abc'.padStart( 6 ,"123465"); // "123abc"
4 'abc'.padStart( 1 ); // "abc"
5 'abc'.padStart( 8 , "0"); // "00000abc"
1 'abc'.padEnd( 5 ); // " abc "
2 'abc'.padEnd( 10 , "foo"); // "abcfoofoof"
3 'abc'.padEnd( 6 , "123456"); // "abc123"
4 'abc'.padEnd( 1 ); // "abc"
5 'abc'.padStart( 8 , "0"); // "abc00000"

使用场景
二进制数据补全

1 '10'.toString( 2 ).padStart( 4 , '0')
日期格式化

1 '02-23'.padStart( 10 , 'YYYY-MM-DD') // 'YYYY-02-23'
2
3 let date = new Date()
4 (date.getMonth() + 1 ).toString().padStart( 2 , '0') // '02'
5 (date.getDate()).toString().padStart( 2 , '0') // '23'

String.prototype.{trimStart,trimEnd}

去除字符串首尾的连续空白符

trimStart() 方法从字符串的开头删除空格,trimLeft()是此方法的别名。
trimEnd() 方法从一个字符串的右端移除空白字符,trimRight 是 trimEnd 的别名。
示例

1 ' dddd '.trimStart() // 'dddd '
2 ' dddd '.trimLeft() // 'dddd '
3 ?
4 ' dddd '.trimEnd() // ' dddd'
5 ' dddd '.trimRight() // ' dddd'

String.prototype.replaceAll

replaceAll() 方法返回一个新字符串,新字符串中所有满足 pattern 的部分都会被replacement 替换。
pattern可以是一个字符串或一个RegExp,replacement可以是一个字符串或一个在每次匹配被调用的函数。
语法

1 str.replaceAll(regexp|substr, newSubstr|function)
参数
regexp|substr,正则或字符串。
newSubstr|function,待替换的字符串或者方法
示例
注意:当使用一个 regex时,您必须设置全局('g')标志

1 'aabbcc'.replaceAll('b', '-') // 'aa--cc'
2 ?
3 'aabbcc'.replaceAll(/b/, '-')
4 // Uncaught TypeError: String.prototype.replaceAll called with a non-global RegExp argument
5 ?
6 'aabbcc'.replaceAll(/b/g, '-');
7 "aa--cc"

String.prototype.matchAll

matchAll() 方法返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。
语法

1 str.matchAll(regexp)

参数

regexp: 正则表达式对象。如果所传参数不是一个正则表达式对象,则会隐式地使用 new RegExp(obj) 将其转换为一个

RegExp 。
RegExp必须是设置了全局模式g的形式,否则会抛出异常TypeError。
示例
和 match 对比,matchAll方法获取捕获组更方便

1 const regexp = /t(e)(st(\d?))/g;
2 const str = 'test1test2';
3 ?
4 str.match(regexp);
5 // Array ['test1', 'test2']
6 ?
7 const array = [...str.matchAll(regexp)];
8 ?
9 array[ 0 ])
10 // Array ["test1", "e", "st1", "1"]
11 ?
12 array[ 1 ]
13 // Array ["test2", "e", "st2", "2"]

Array 方法的扩展

Array.prototype.includes()

includes() 方法用来判断一个数组是否包含一个指定的值,如果包含则返回 true,否则返回 false。

语法

1 arr.includes(valueToFind[, fromIndex])

参数
valueToFind,需要查找的元素值。
fromIndex,可选,从fromIndex 索引处开始查找 valueToFind。如果为负值(即从末尾开始往前跳 fromIndex 的绝对值个索
引,然后往后搜寻)。默认为 0 。

示例

如果只想知道某个值是否在数组中存在,使用includes会更方便

1 const arr = ['es6', 'es7', 'es8']
2 arr.includes('es7') // true
3 arr.includes('es7', 1 ) // true
4 arr.includes('es7', 2 ) // false
5 arr.includes("es7", - 1 ) // false
6 arr.includes("es7", - 2 ) // true

使用 includes()查找字符串是区分大小写的

1 const arr = ["es6", "es7", "es8", "a"];
2 arr.includes("ES6"); // false

使用 includes()只能判断简单类型的数据,对于复杂类型的数据,比如对象类型的数组,二维数组,这些是无法判断的

1 const arr = ['es6', ['es7', 'es8'], 'es9',{name:"jimmy"}]
2 arr.includes(["es7", "es8"]); // false
3 arr.includes({name:"jimmy"}); // false

能识别NaN,indexOf是不能识别NaN的

1 const arr = ['es6', 'es7', NaN, 'es8']
2 arr.includes(NaN) // true
3 arr.indexOf(NaN) // -

Array.prototype.flat()

flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回

语法

1 var newArray = arr.flat([depth])

参数
depth 可选,指定要提取嵌套数组的结构深度,默认值为 1 。

示例
扁平化嵌套数组

1 const arr1 = [ 0 , 1 , 2 , [ 3 , 4 ]]
2 arr1.flat() // [0, 1, 2, 3, 4]
3 const arr2 = [ 0 , 1 , 2 , [[[ 3 , 4 ]]]];
4 arr2.flat( 2 ) // [0, 1, 2, [3, 4]]

使用 Infinity,可展开任意深度的嵌套数组

1 var arr4 = [ 1 , 2 , [ 3 , 4 , [ 5 , 6 , [ 7 , 8 , [ 9 , 10 ]]]]];
2 arr4.flat(Infinity) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

flat() 方法会移除数组中的空项

1 var arr5 = [ 1 , 2 , , 4 , 5 ];
2 arr5.flat(); // [1, 2, 4, 5]

Array.prototype.flatMap()

flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。
从方法的名字上也可以看出来它包含两部分功能一个是 map,一个是 flat(深度为 1 )。

语法

1 var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) {
2 // 返回新数组的元素
3 }[, thisArg])

参数
callback,可以生成一个新数组中的元素的函数,可以传入三个参数:
currentValue:当前正在数组中处理的元素
index,可选,数组中正在处理的当前元素的索引。
array,可选,被调用的 map 数组
thisArg可选,执行 callback 函数时 使用的this 值

示例
简单对比map和flatMap的区别

1 const numbers = [ 1 , 2 , 3 ]
2 numbers.map(x => [x * 2 ]) // [[2], [4], [6]]
3 numbers.flatMap(x => [x * 2 ]) // [2, 4, 6]

进一步对比

1 let arr1 = ["it's Sunny in", "", "California"];
2 ?
3 arr1.map(x => x.split(" "));
4 // [["it's","Sunny","in"],[""],["California"]]
5 ?
6 arr1.flatMap(x => x.split(" "));
7 // ["it's","Sunny","in", "", "California"]

Array.prototype.at

at() 方法接收一个整数值并返回该索引的项目,允许正数和负数。负整数从数组中的最后一个项目开始倒数。

语法

1 at(index)

参数
index,要返回的数组元素的索引(位置)。当传递负数时,支持从数组末端开始的相对索引;也就是说,如果使用负数,返回
的元素将从数组的末端开始倒数。

返回值
匹配给定索引的数组中的元素。如果找不到指定的索引,则返回undefined

示例
使用at(-1)返回数组的最后一项,相对使用数组的length获取,要方便很多

1 const array = [ 5 , 12 , 8 , 130 , 44 ]
2 array.at(- 1 ) // 44
3 array.at(- 2 ) // 130
4 array.at( 2 ) // 12
5 ?
6 let index = 2 ;

Object 方法的扩展

Object.values()

Object.values 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。

语法

1 Object.values(obj)

示例

1 var obj = { foo: 'bar', baz: 42 };
2 console.log(Object.values(obj)); // ['bar', 42]
3 ?
4 // array like object with random key ordering
5 // when we use numeric keys, the value returned in a numerical order according to the keys
6 var an_obj = { 100 : 'a', 2 : 'b', 7 : 'c' };
7 console.log(Object.values(an_obj)); // ['b', 'c', 'a']
8 ?
9 // getFoo is property which isn't enumerable
10 var my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; } } });
11 my_obj.foo = 'bar';
12 console.log(Object.values(my_obj)); // ['bar']
13 ?
14 // non-object argument will be coerced to an object
15 console.log(Object.values('foo')); // ['f', 'o', 'o']

Object.entries()

Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区
别在于 for-in 循环还会枚举原型链中的属性)

语法

1 Object.entries(obj)

示例

1 const obj = { foo: 'bar', baz: 42 };
2 console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
3 ?
4 // array like object
5 const obj = { 0 : 'a', 1 : 'b', 2 : 'c' };
6 console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
7 ?
8 // array like object with random key ordering
9 const anObj = { 100 : 'a', 2 : 'b', 7 : 'c' };
10 console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]
11 ?
12 // getFoo is property which isn't enumerable
13 const myObj = Object.create({}, { getFoo: { value() { return this.foo; } } });
14 myObj.foo = 'bar';
15 console.log(Object.entries(myObj)); // [ ['foo', 'bar'] ]
16 ?
17 // non-object argument will be coerced to an object
18 console.log(Object.entries('foo')); // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ]
19 ?
20 // iterate through key-value gracefully
21 const obj = { a: 5 , b: 7 , c: 9 };
22 for (const [key, value] of Object.entries(obj)) {
23 console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
24 }
25 ?
26 // Or, using array extras
27 Object.entries(obj).forEach(([key, value]) => {
28 console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
29 });

Object. fromEntries

Object.fromEntries() 把键值对列表转换为一个对象。这个方法是和 Object.entries() 是互逆的操作。

语法

1 Object.fromEntries(iterable)

参数
iterable,类似Array、Map或者其他实现了可迭代协议的可迭代对象

示例
map和array转为对象

1 const map = new Map([ ['foo', 'bar'], ['baz', 42 ] ]);
2 const obj = Object.fromEntries(map);
3 console.log(obj); // { foo: "bar", baz: 42 }
4 ?
5 const arr = [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ];
6 const obj = Object.fromEntries(arr);
7 console.log(obj); // { 0: "a", 1: "b", 2: "c" }

处理Object,做过滤等操作

1 const object1 = { a: 1 , b: 2 , c: 3 };
2 ?
3 const object2 = Object.fromEntries(
4 Object.entries(object1)
5 .filter(([ key, val ]) => val > 1 )
6 );
7 ?
8 console.log(object2);
9 // {b: 2, c: 3}

Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors() 方法用来获取一个对象的所有自身属性的描述符

语法

1 Object.getOwnPropertyDescriptors(obj)

示例

1 const obj = {
2 a: "test",
3 b: 11 ,
4 };
5 Object.getOwnPropertyDescriptors(obj);
6 // output
7 {
8 : {
9 configurable: true
10 enumerable: true
11 value: "test"
12 writable: true
13 },
14 : {
15 configurable: true
16 enumerable: true
17 value: 11
18 writable: true
19 }
20 }

浅拷?一个对象,并且拷?对象的属性特性和原型方法。相比较Object.assign拷?更完整。

1 Object.create(
2 Object.getPrototypeOf(obj),
3 Object.getOwnPropertyDescriptors(obj)
4 );

Object.prototype.hasOwn

用于判断Object是否存在某个属性,同hasOwnProperty。

promise

Promise.prototype.finally()

Promise.prototype.finally() 方法返回一个Promise,在promise执行结束时,无论结果是fulfilled或者是rejected,在执行then()和
catch()后,都会执行finally指定的回调函数。
这为指定执行完promise后,无论结果是fulfilled还是rejected都需要执行的代码提供了一种方式,避免同样的语句需要在then()和
catch()中各写一次的情况。

示例
如果你想在 promise 执行完毕后无论其结果怎样都做一些处理或清理时,finally() 方法可能是有用的。
在promise结束之后将loading置为false

1 let isLoading = true;
2 ?
3 fetch(myRequest).then(function(response) {
4 var contentType = response.headers.get("content-type");
5 if(contentType && contentType.includes("application/json")) {
6 return response.json();
7 }
8 throw new TypeError("Oops, we haven't got JSON!");
9 })
10 .then(function(json) { /* process your JSON further */ })
11 .catch(function(error) { console.log(error); })
12 .finally(function() { isLoading = false; });

Promise.allSettled()

Promise.allSettled()方法返回一个在所有给定的promise都已经(fulfilled或rejected后)的promise,并带有一个对象数组,每个对
象表示对应的promise结果。
当有多个彼此不依赖的异步任务成功完成时,或者总是想知道每个promise的结果时,通常使用它。
相比之下,Promise.all()更适合彼此相互依赖或者在其中任何一个reject时立即结束。

语法

1 Promise.allSettled(iterable)

参数
iterable,一个可迭代对象,其中每个成员都是Promise。

示例

1 const promise1 = Promise.resolve( 3 );
2 const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100 , 'foo'));
3 const promises = [promise1, promise2];
4 ?
5 Promise.allSettled(promises).
6 then((results) => results.forEach((result) => console.log(result.status)));
7
8 // expected output:
9 // "fulfilled"
10 // "rejected"

Promise.any

Promise.any() 接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。
如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 。
本质上,这个方法和Promise.all是相反的。

语法

1 Promise.any(iterable)
参数
iterable,一个可迭代的promise对象

示例
当需要有多个请求,而不确定那个能成功的时候使用此方法比较合适

1 const pErr = new Promise((resolve, reject) => {
2 reject("总是失败");
3 });
4 ?
5 const pSlow = new Promise((resolve, reject) => {
6 setTimeout(resolve, 500 , "最终完成");
7 });
8 ?
9 const pFast = new Promise((resolve, reject) => {
10 setTimeout(resolve, 100 , "很快完成");
11 });
12 ?
13 Promise.any([pErr, pSlow, pFast]).then((value) => {
14 console.log(value);
15 // pFast fulfils first
16 })
17 // 期望输出: "很快完成"

表达式和运算符

求幂 (**)

求幂运算符(**)返回将第一个操作数加到第二个操作数的幂的结果。它等效于Math.pow,不同之处在于它也接受BigInts作为操作
数。

语法

1 Operator: var1 ** var

示例
求幂运算符是是右结合的: a ** b ** c 等于 a ** ( b ** c )

1 2 ** 3 ** 2 // 512
2 2 ** ( 3 ** 2 ) // 512
3 ( 2 ** 3 ) ** 2 // 64

不能立刻将一个一元运算符(+/-/~/!/delete/void/typeof)放在基数前,这样做只会导致一个语法错误

1 - 2 ** 2 ;
2 // 4 in Bash, -4 in other languages.
3 // This is invalid in JavaScript, as the operation is ambiguous.
4 ?
5 ?
6 - ( 2 ** 2 );
7 // -4 in JavaScript and the author's intention is unambiguous.
8 ?
9 // ok
10 - ( 2 ** 2 ) // -
11 (- 2 ) ** 2 // 4

可选链操作符 ?.

可选链操作符( ?. )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。

?. 操作符的功能类似于. 链式操作符,不同之处在于,在引用为 null 或者 undefined 的情况下不会引起错误,该表达式短路返回值是
undefined。
与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。
当尝试访问可能不存在的对象属性时,可选链操作符将会使表达式更短、更简明。
在探索一个对象的内容时,如果不能确定哪些属性必定存在,可选链操作符也是很有帮助的。

语法

1 obj?.prop
2 obj?.[expr]
3 arr?.[index]
4 func?.(args)

示例
可选链不能用于赋值

1 let customer = {
2 name: "Carl",
3 details: {
4 age: 82 ,
5 location: "Paradise Falls" // details 的 address 属性未有定义
6 }
7 };
8 let customerCity = customer.details?.address?.city;
9 ?
10 // 可选链也可以和函数调用一起使用
11 let duration = vacations.trip?.getTime?.();

空值合并运算符 ??

空值合并操作符( ?? )是一个逻辑操作符,当左侧的操作数为 null或者undefined时,返回其右侧操作数,否则返回左侧操作数。

语法

1 leftExpr ?? rightExpr

示例
相较于 || 运算符,可以避免为 0 或者' '赋值失败的副作用

1 const nullValue = null;
2 const emptyText = ""; // 空字符串,是一个假值,Boolean("") === false
3 const someNumber = 42 ;
4 ?
5 const valA = nullValue ?? "valA 的默认值";
6 const valB = emptyText ?? "valB 的默认值";
7 const valC = someNumber ?? 0 ;
8 ?
9 console.log(valA); // "valA 的默认值"
10 console.log(valB); // ""(空字符串虽然是假值,但不是 null 或者 undefined)
11 console.log(valC); // 42

不能与 && 或 || 操作符共用

1 null || undefined ?? "foo"; // 抛出 SyntaxError
2 true || undefined ?? "foo"; // 抛出 SyntaxError
3 ?
4 (null || undefined ) ?? "foo"; // 返回 "foo"

逻辑与赋值 &&=

x &&= y等效于:x && (x = y),只有在x为真的时候,才会将y赋值给x

语法

1 expr1 &&= expr

示例

1 let x = 0 ;
2 let y = 1 ;
3 ?
4 x &&= 0 ; // 0
5 x &&= 1 ; // 0
6 y &&= 1 ; // 1
7 y &&= 0 ; // 0

逻辑或赋值 ||=

逻辑或赋值(x ||= y)运算仅在 x 为false时赋值。x ||= y 等同于:x || (x = y);

语法

1 expr1 ||= expr

示例
可用做默认赋值

1 let a = {}
2 a.b ||= 4

逻辑空赋值??=

逻辑空赋值运算符 (x ??= y) 仅在 x 是 (null 或 undefined) 时对其赋值。x ??= y 等价于:x ?? (x = y);

语法

1 expr1 ??= expr

示例

1 function config(options) {
2 options.duration ??= 100 ;
3 options.speed ??= 25 ;
4 return options;
5 }
6 ?
7 config({ duration: 125 }); // { duration: 125, speed: 25 }
8 config({}); // { duration: 100, speed: 25 }

可选的Catch Binding

在 ES10 之前我们都是这样捕获异常的,在这里 err 是必须的参数,在 ES10 可以省略这个参数

1 try {
2 // tryCode
3 } catch (err) {
4 // catchCode
5 }
6 ?
7 try {
8 console.log('Foobar')
9 } catch {
10 console.error('Bar')
11 }

示例
验证参数是否为json格式

1 const validJSON = json => {
2 try {
3 JSON.parse(json)
4 return true
5 } catch {
6 return false
7 }
8 }

globalThis

在以前,从不同的 JavaScript 环境中获取全局对象需要不同的语句。
在 Web 中,可以通过 window、self 取到全局对象,在 Node.js 中,它们都无法获取,必须使用 global。
在松散模式下,可以在函数中返回 this 来获取全局对象,但是在严格模式和模块环境下,this 会返回 undefined。

以前想要获取全局对象,可通过一个全局函数

1 const getGlobal = () => {
2 if (typeof self !== 'undefined') {
3 return self
4 }
5 if (typeof window !== 'undefined') {
6 return window
7 }
8 if (typeof global !== 'undefined') {
9 return global
10 }
11 throw new Error('无法找到全局对象')
12 }
13 const globals = getGlobal()
14 console.log(globals)

现在globalThis 提供了一个标准的方式来获取不同环境下的全局 this 对象(也就是全局对象自身)。
不像 window 或者 self 这些属性,它确保可以在有无窗口的各种环境下正常工作。
所以,你可以安心的使用 globalThis,不必担心它的运行环境。
为便于记忆,你只需要记住,全局作用域中的 this 就是globalThis。
以后就用globalThis就行了。

BigInt

BigInt 是一种内置对象,它提供了一种方法来表示大于 2 的 53 次方 - 1 的整数。
这原本是 Javascript中可以用 Number 表示的最大数字。BigInt 可以表示任意大的整数。

示例

BigInt不能用于 [Math] 对象中的方法;
不能和任何 [Number] 实例混合运算,两者必须转换成同一种类型。
在两种类型来回转换时要小心,因为 BigInt 变量在转换成 [Number] 变量时可能会丢失精度。

数字后面增加n

1 const bigInt = 9007199254740993n
2 console.log(bigInt)
3 console.log(typeof bigInt) // bigint
4 ?
5 // `BigInt` 和 [`Number`]不是严格相等的,但是宽松相等的。
6 console.log(1n == 1 ) // true
7 console.log(1n === 1 ) // false
8 ?
9 // `Number` 和 `BigInt` 可以进行比较。
10 1n < 2 // true
11 2n > 1 // true

使用 BigInt 函数

1 const bigIntNum = BigInt(9007199254740993n)
2 console.log(bigIntNum)
3 ?
4 let number = BigInt( 2 );
5 let a = number + 2n; // 4n
6 let b = number * 10n; // 20n
7 let c = number - 10n; // -8n
8 console.log(a);
9 console.log(b);
10 console.log(c);

for await of

异步迭代器(for-await-of):循环等待每个Promise对象变为resolved状态才进入下一步。

语法
1 for await (variable of iterable) {
2 statement
3 }

参数
variable,在每次迭代中,将不同属性的值分配给变量。变量有可能以const, let, 或者 var来声明。
iterable,被迭代枚举其属性的对象。与 for...of 相比,这里的对象可以返回 Promise,如果是这样,那么 variable 将是
Promise 所包含的值,否则是值本身。

示例

与for...of 使用对比,for...of为同步执行

1 function TimeOut(time){
2 return new Promise(function(resolve, reject) {
3 setTimeout(function() {
4 resolve(time)
5 }, time)
6 })
7 }
8 async function test() {
9 let arr = [TimeOut( 2000 ), TimeOut( 1000 ), TimeOut( 3000 )]
10 for (let item of arr) {
11 console.log(Date.now(),item.then(console.log))
12 }
13 }
14 ?
15 test()
16 // 先打印
17 1645761256834 Promise {<pending>}
18 1645761256834 Promise {<pending>}
19 1645761256834 Promise {<pending>}
20 // 然后
21 1000
22 2000
23 3000

for await of 等待每个Promise对象变为resolved状态才进入下一步

1 function TimeOut(time) {
2 return new Promise(function(resolve, reject) {
3 setTimeout(function() {
4 resolve(time)
5 }, time)
6 })
7 }
8 ?
9 async function test() {
10 let arr = [TimeOut( 2000 ), TimeOut( 1000 ), TimeOut( 3000 )]
11 for await (let item of arr) {
12 console.log(Date.now(), item)
13 }
14 }
15 test()
16 // 1645761360856 2000
17 // 1645761360857 1000
18 // 1645761361859 3000

Error Cause

Error Cause 是中国首个进入 Stage 4 的 TC39 提案。Chrome 93 版本已支持使用 Error Cause
这一提案为 JavaScript 中的 Error 构造函数新增了一个属性 cause,我们可以通过这个属性为抛出的错误附加错误原因,来清晰的跨
越多个调用栈传递错误上下文信息。

示例

1 try {
2 return await fetch('//unintelligible-url-a') // 抛出一个 low level 错误
3 .catch(err => {
4 throw new Error('Download raw resource failed', { cause: err }) // 将 low level 错误包装成一个 high level、易懂的错误
5 })
6 } catch (err) {
7 console.log(err)
8 console.log('Caused by', err.cause)
9 }
10 ?
11 // Error: Download raw resource failed
12 // Caused by TypeError: Failed to fetch

还有一些大家耳熟能详的新特性,比如 async/await,Object Rest & Spread,还有正则和class静态语法块的扩展,这里有不

一一展开了。感兴趣的小伙伴可以自行查阅。
相关连接

TC39已完成草案 https://github.com/tc39/proposals/blob/main/finished-proposals.md
2022 年了,这些ES7-ES12的知识点你都掌握了嘛? https://mp.weixin.qq.com/s/josaMwI15sYwFXcXh07Jaw

文章来源:https://blog.csdn.net/alnorthword/article/details/135150786
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。