为了保证可读性,本文采用意译而非直译。
ECMAScript 2015,也称为 ES6,是一个花了 6 年时间完成的主要版本。从那时起,负责 ECMAScript 标准开发的技术委员会 39 (TC39)每年都会发布该标准的新版本。这个年度发布周期简化了这个过程,并使新特性快速可用,JavaScript 社区对此表示欢迎。
今年,ECMAScript 2019(简称 ES2019)将会发布。新功能包括 Object.fromEntries()
,trimStart()
,trimEnd()
,flat()
,flatMap()
,symbol 对象的 description 属性,可选的catch
绑定等。
好消息是这些功能已经在最新版本的 Firefox 和 Chrome 中实现,并且它们也可以被转换,以便旧版浏览器能够处理它们。
1. Object.fromEntries()
在 JavaScript 中,将数据从一种格式转换为另一种格式非常常见。为了便于将对象转换为数组,ES2017 引入了 Object.entrie()
方法。此方法将 对象 作为参数,并以 [key,value]
的形式返回对象自己的可枚举字符串键控属性对的数组。例如:
const obj = {one: 1, two: 2, three: 3};
console.log(Object.entries(obj));
// => [["one", 1], ["two", 2], ["three", 3]]
但是如果我们想要做相反的事情并将键值对列表转换为对象呢?某些编程语言(如 Python)为此提供了 dict()
函数。在 Underscore.js
和Lodash中还有 _.fromPairs
函数。
ES2019 引入 Object.fromEntries()
方法为 JavaScript 带来类似的功能, 此静态方法允许你轻松地将键值对列表转换为对象:
const myArray = [['one', 1], ['two', 2], ['three', 3]];
const obj = Object.fromEntries(myArray);
console.log(obj); // => {one: 1, two: 2, three: 3}
如你所见,Object.fromEntries()
与 Object.entries()
所做的事情正好相反。虽然以前可以实现 Object.fromEntries()相同的功能,但它实现方式有些复杂:
const myArray = [['one', 1], ['two', 2], ['three', 3]];
const Array.from(myArray).reduce((acc, [key, val])
=> Object.assign(acc, {[key]: val}), {})
console.log(obj); // => {one: 1, two: 2, three: 3}
请记住,传递给 Object.fromEntries()
的参数可以是实现可迭代协议的任何对象,只要它返回一个两元素,类似于数组的对象即可。
例如,在以下代码中,Object.fromEntries()
将 Map 对象作为参数,并创建一个新对象,其键和对应值由 Map 中的对给出:
const map = new Map();
map.set('one', 1);
map.set('two', 2);
const obj = Object.fromEntries(map);
console.log(obj); // => {one: 1, two: 2}
Object.fromEntries()
方法对于转换对象也非常有用,思考以下代码:
const obj = {a: 4, b: 9, c: 16};
// 将对象转换为数组
const arr = Object.entries(obj);
// 计算数字的平方根
const map = arr.map(([key, val]) => [key, Math.sqrt(val)]);
// 将数组转换回对象
const obj2 = Object.fromEntries(map);
console.log(obj2); // => {a: 2, b: 3, c: 4}
上述代码将对象中的值转换为其平方根。为此,它首先将对象转换为数组,然后使用 map()
方法获取数组中值的平方根, 结果是可以转换回对象的数组。
使用 Object.fromEntries()
的另一种情况是处理 URL 的查询字符串,如本例所示
const paramsString = 'param1=foo¶m2=baz';
const searchParams = new URLSearchParams(paramsString);
Object.fromEntries(searchParams); // => {param1: "foo", param2: "baz"}
此代码中,查询字符串将传递给 URLSearchParams()
构造函数。然后将返回值(即 URLSearchParams
对象实例)传递给Object.fromEntries()
方法,结果是一个包含每个参数作为属性的对象。
Object.fromEntries()
方法目前是第 4 阶段提案,这意味着它已准备好包含在 ES2019 标准中。
2. trimStart() and trimEnd()
trimStart()
和 trimEnd()
方法在实现与 trimLeft()
和trimRight()
相同。这些方法目前处于第 4 阶段,将被添加到规范中,以便与 padStart()
和padEnd()
保持一致,来看一些例子:
const str = "string";
// es2019
console.log(str.trimStart()); // => "string"
console.log(str.trimEnd()); // => "string"
// 相同结果
console.log(str.trimLeft()); // => "string"
console.log(str.trimRight()); // => "string"
对于 Web 兼容性,trimLeft()
和trimRight()
将保留为trimStart()
和trimEnd()
的别名。
3. flat() and flatMap()
flat()
方法可以将多维数组展平成一维数组
const arr = ['a', 'b', ['c', 'd']];
const flattened = arr.flat();
console.log(flattened); // => ["a", "b", "c", "d"]
以前,我们经常使用 reduce()
或concat()
来展平多维数组:
const arr = ['a', 'b', ['c', 'd']];
const flattend = [].concat.apply([], arr);
// or
// const flattened = [].concat(...arr);
console.log(flattened); // => ["a", "b", "c", "d"]
请注意,如果提供的数组中有空值,它们会被丢弃:
const arr = ['a', , , 'b', ['c', 'd']];
const flattened = arr.flat();
console.log(flattened); // => ["a", "b", "c", "d"]
flat()
还接受一个可选参数,该参数指定嵌套数组应该被展平的级别数。如果未提供参数,则将使用默认值1
:
const arr = [10, [20, [30]]];
console.log(arr.flat()); // => [10, 20, [30]]
console.log(arr.flat(1)); // => [10, 20, [30]]
console.log(arr.flat(2)); // => [10, 20, 30]
flatMap()
方法将 map()
和flat()
组合成一个方法。它首先使用提供的函数的返回值创建一个新数组,然后连接该数组的所有子数组元素。来个例子:
const arr = [4.25, 19.99, 25.5];
console.log(arr.map(value => [Math.round(value)]));
// => [[4], [20], [26]]
console.log(arr.flatMap(value => [Math.round(value)]));
// => [4, 20, 26]
数组将被展平的深度级别为1
. 如果要从结果中删除项目,只需返回一个空数组:
const arr = [[7.1], [8.1], [9.1], [10.1], [11.1]];
// do not include items bigger than 9
arr.flatMap(value => {if (value >= 10) {return [];
} else {return Math.round(value);
}
});
// returns:
// => [7, 8, 9]
除了正在处理的当前元素外,回调函数还将接收元素的索引和对数组本身的引用。flat()
和 flatMap()
方法目前处于第 4 阶段。
4.Symbol 对象的 description 属性
在创建 Symbol 时,可以为调试目的向其添加description
(描述)。有时候,能够直接访问代码中的description
是很有用的。
ES2019 中为 Symbol
对象添加了只读属性 description
,该对象返回包含 Symbol
描述的字符串。
let sym = Symbol('foo');
console.log(sym.description); // => foo
sym = Symbol();
console.log(sym.description); // => undefined
// create a global symbol
sym = Symbol.for('bar');
console.log(sym.description); // => bar
5. 可选的 catch
try catch
语句中的 catch
有时候并没有用,思考下面代码:
try {// 使用浏览器可能尚未实现的功能} catch (unused) {// 这里回调函数中已经帮我们处理好的错误}
此代码中的 catch
回调的信息并没有用处。但这样写是为了避免 SyntaxError
错误。ES2019 可以省略 catch
周围的括号:
try {// ...} catch {// ....}
另外:ES2020 的 String.prototype.matchAll
matchAll()
方法是 ES2020 第 4 阶段提议,它针对正则表达式返回所有匹配(包括捕获组)的迭代器对象。
为了与 match()
方法保持一致,TC39 选择了 “matchAll” 而不是其他建议的名称,例如“matches”或 Ruby 的“scan”。看个简单的例子:
const re = /(Dr\.)\w+/g;
const str = 'Dr. Smith and Dr. Anderson';
const matches = str.matchAll(re);
for (const match of matches) {console.log(match);
}
// logs:
// => ["Dr. Smith", "Dr.", index: 0, input: "Dr. Smith and Dr. Anderson", groups: undefined]
// => ["Dr. Anderson", "Dr.", index: 14, input: "Dr. Smith and Dr. Anderson", groups: undefined]
此正则表达式中的捕获组匹配字符 “Dr”,后跟一个点和一个空格。\w+
匹配任何单词字符一次或多次。并且g
标志指示引擎在整个字符串中搜索模式。
之前,必须在循环中使用 exec()
方法来实现相同的结果,这不是非常有效:
const re = /(Dr\.) \w+/g;
const str = 'Dr. Smith and Dr. Anderson';
let matches;
while ((matches = re.exec(str)) !== null) {console.log(matches);
}
// logs:
// => ["Dr. Smith", "Dr.", index: 0, input: "Dr. Smith and Dr. Anderson", groups: undefined]
// => ["Dr. Anderson", "Dr.", index: 14, input: "Dr. Smith and Dr. Anderson", groups: undefined]
重要的是要注意尽管 match()
方法可以与全局标志g
一起使用来访问所有匹配,但它不提供匹配的捕获组或索引位置。比较以下代码:
const re = /page (\d+)/g;
const str = 'page 2 and page 10';
console.log(str.match(re));
// => ["page 2", "page 10"]
console.log(...str.matchAll(re));
// => ["page 2", "2", index: 0, input: "page 2 and page 10", groups: undefined]
// => ["page 10", "10", index: 11, input: "page 2 and page 10", groups: undefined]
总结
在这篇文章中,我们仔细研究了 ES2019 中引入的几个关键特性,包括Object.fromEntries()
,trimStart()
, trimEnd()
, flat()
, flatMap()
,symbol
对象的 description 属性以及可选的catch
。
尽管一些浏览器还没有完全实现这些特性,但可以使用 Babel 和其他 JavaScript 转换器,仍然可以在项目中使用它们。
交流
干货系列文章汇总如下,觉得不错点个 Star,欢迎 加群 互相学习。
https://github.com/qq44924588…
我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复 福利,即可看到福利,你懂的。