一、ECMAScript10新特性
1、可选的 catch 变量绑定
在 ES10 之前,我们必须通过语法为 catch 子句绑定异常变量,无论是否有必要。很多时候 catch 块是多余的,而 ES10 使我们能够简单的把变量省略掉。
//之前是
try {} catch(e) {}
//ES10之后可以写成,
try {} catch {}//省掉了变量e
2、JSON超集
什么是 JSON 超集?简单来说就是 JSON 是 ECMAScript 的子集,也就是说让 ECMAScript 兼容 JSON 的内容所支持的全部文本。
ECMAScript 在标准 JSON.parse 部分阐明了 JSON 确为其一个子集,但由于 JSON 的内容可以正常包含 U+2028 行分隔符与 U+2029 段落分隔符,而 ECMAScript 却不行,所以,该草案旨在解决这一问题。在这之前,如果你使用JSON.parse() 执行带如上特殊字符的字符串时,只会收到SyntaxError 的错误提示。该草案同样是向后兼容的,其对用户唯一的影响是保持原样,即在暂不支持特殊字符解析的运行环境中保持报错 SyntaxError 。
3、Symbol 对象的 description 属性
ES10 中为 Symbol 对象添加了只读属性 description ,该对象返回包含 Symbol 描述的字符串。在创建Symbol时向其添加description (描述),能够直接访问description ,对调试是很有用的。
let map = new Map().set('foo', true).set('bar', false);
let arr = Array.from(map);
let set = new Set(map.values());
let obj = { foo: true, bar: false };
//下一句 Object.entries() 方法返回给定对象 obj 自身可枚举属性的键值对数组,
//形如:[["foo",true],["bar",false]]
let newMap = new Map(Object.entries(obj));
4、修订Function.prototype.toString
函数原型上的方法toString()现在返回精确字符,包括空格和注释。
let r;
r = JSON.stringify("❤"); //正常的UTF-8字符原样输出
console.log(r); //>> "❤"
r = JSON.stringify('\u2764'); //正常的UTF-8字符编码,输出解码之后的模样
console.log(r); //>> "❤"
r = JSON.stringify("\uDF06\uD834"); //不正常的UTF-8字符编码,则以unicode形式输出
console.log(r); //>> "\udf06\ud834"
r = JSON.stringify("\uDEAD"); //不正常的UTF-8字符编码,则以unicode形式输出
console.log(r); //>> "\udead"
5、Object.fromEntries
在 JavaScript 操作中,数据在各种数据结构之间的转换都是很容易的,比如 Map 到数组、Map 到 Set、对象到 Map 等等。
let r;
r = JSON.stringify("❤"); //正常的UTF-8字符原样输出
console.log(r); //>> "❤"
r = JSON.stringify('\u2764'); //正常的UTF-8字符编码,输出解码之后的模样
console.log(r); //>> "❤"
r = JSON.stringify("\uDF06\uD834"); //不正常的UTF-8字符编码,则以unicode形式输出
console.log(r); //>> "\udf06\ud834"
r = JSON.stringify("\uDEAD"); //不正常的UTF-8字符编码,则以unicode形式输出
console.log(r); //>> "\udead"
但是如果我们需要将一个键值对列表转换为对象,就要写点费劲的代码了
let map = new Map().set("foo", true).set("bar", false);
let obj = Array.from(map).reduce((acc, [key, val]) => {
return Object.assign(acc, {
[key]: val
});
}, {});
该特性的目的在于为对象添加一个新的静态方法 Object.fromEntries,用于将符合键值对的列表(例如 Map、数组等)转换为一个对象。上一块的代码中的转换逻辑,现在我们只需要一行代码即可搞定。
const map = new Map().set("foo", true).set("bar", false);
let obj = Object.fromEntries(map);
6、更加友好的 JSON.stringify
ES10 之前,当你使用 JSON.stringify() 处理无法用 UTF-8 编码表示的字符时(U+D800 至 U+DFFF),返回的结果会是一个乱码 Unicode 字符“�”。该特性提出用JSON.stringify()来安全的表示这些不正常的UTF-8字符。
let r;
r = JSON.stringify("❤"); //正常的UTF-8字符原样输出
console.log(r); //>> "❤"
r = JSON.stringify('\u2764'); //正常的UTF-8字符编码,输出解码之后的模样
console.log(r); //>> "❤"
r = JSON.stringify("\uDF06\uD834"); //不正常的UTF-8字符编码,则以unicode形式输出
console.log(r); //>> "\udf06\ud834"
r = JSON.stringify("\uDEAD"); //不正常的UTF-8字符编码,则以unicode形式输出
console.log(r); //>> "\udead"
7、String.prototype.{trimStart,trimEnd}
新增了String的trimStart()方法和trimEnd()方法,这两个方法很好理解,分别去除字符串首、尾的空白字符,就不举例占篇幅了。
8、Array.prototype.{flat,flatMap}
这个特性新创造了两个方法,其中:
来看几个例子解释一下,首先 flat() 方法支持多维数组的扁平化,其中Infinity可以将多维数组压扁成一维数组。
let r;
r = ["1", ["8", ["9", ["1"]]]].flat();//4维数组,默认降维1,变成3维数组
console.log(r); //>> [ '1', '8', [ '9', ['1'] ] ]
r = ["1", ["8", ["9", ["1"]]]].flat(2); //4维数组,降维2,变成2维数组
console.log(r); //>> [ '1', '8', '9', ['1'] ]
r = ["1", ["8", ["9", ["1"]]]].flat(Infinity);//4维数组,最多变成1维数组
console.log(r); //>> [ '1', '8', '9', '1' ]
接着来看看flatMap()
let r;
r = ["I love", "coffe 1891"].map(item => item.split(" "));
console.log(r); //>> [ [ 'I', 'love' ], [ 'coffe', '1891' ] ]
r = ["I love", "coffe 1891"].flatMap(item => item.split(" "));
console.log(r); //>>[ 'I', 'love', 'coffe', '1891' ]
二、ECMAScript11新特性
1、String.prototype.matchAll
matchAll() 方法返回一个包含所有匹配正则表达式及分组捕获结果的迭代器(iterator)。 在 matchAll 出现之前,通过在循环中调用Regexp.exec来获取所有匹配项信息(Regexp需使用/g标志):
const regexp = RegExp('foo*','g');
const str = 'coffe football, foosball';
while ((matches = regexp.exec(str)) !== null) {
console.log(`找到 ${matches[0]},下一轮循环从位置 ${regexp.lastIndex} 开始`);
//>> 找到 foo,下一轮循环从位置 9 开始
//>> 找到 foo,下一轮循环从位置 19 开始
}
如果使用matchAll ,就可以不必使用while循环加exec方式(且正则表达式需使用/g标志)。使用matchAll 会得到一个迭代器的返回值,配合 for...of,array spread,Array.from() 可以更方便实现功能。
const regexp = RegExp('foo*','g');
const str = 'coffe football, foosball';
let matches = str.matchAll(regexp);
for (const match of matches) {
console.log(match);
}
//>> [ "foo" ]
//>> [ "foo" ]
//注意:
//matches的迭代器在for..of之后已经被消耗掉了,
//需要再次调用matchAll创建一个新的迭代器
matches = str.matchAll(regexp);
let arr = Array.from(matches, m => m[0]);
console.log(arr);
//>> [ "foo", "foo" ]
2、import()函数
这个特性为JavaScript添加了一个类函数(function-like)的import()功能,以便可以像函数传参那样传入参数实现动态(没错,import是静态引用的)引用模块(module)。下面有个单页应用简单示例,演示了用import()开启懒加载。
内容将会加载到这里!
请注意import()和import的区别:
如果模块采用default的形式对外暴露接口,则可用default属性直接获得。
import('./module.js')
.then(module => {
console.log(module.default);//直接通过default属性获得模块暴露的接口
});
3、Promise.allSettled
为什么要有Promise.allSettled()?
举例说明,比如各位用户在页面上面同时填了3个独立的表单,这三个表单分三个接口提交到后端,三个接口独立,没有顺序依赖,这个时候我们需要等到请求全部完成后给与用户提示表单提交的情况。
在多个promise同时进行时咱们很快会想到使用Promise.all来进行包装,但是由于Promise.all的一票否决的特性,三个提交中若前面任意一个提交失败,则后面的表单也不会进行提交了,这就与咱们需求不符合。
Promise.allSettled跟Promise.all类似,其参数接受一个Promise的数组,返回一个新的Promise,唯一的不同在于,其没有一票否决的特性,也就是说当Promise全部处理完成后我们可以拿到每个Promise的状态,而不管其是否处理成功。
Promise.allSettled([Promise.resolve("coffe"), Promise.reject("1891")]).then(
arr => {
console.log(arr); //>> [ { status: "fulfilled", value: "coffe"},
//>> { status: "rejected", reason: "1891" } ]
}
);