编者按:本文译者奇舞团前端开发工程师刘冰晶。
随着ES2019新增特性的发布,ECMAScript标准又迎来了更新。
如今,这些特性已经可以用在node、Chrome、FireFox以及Safari中。如果想要在旧的浏览器中使用这些新特性,我们可以使用Babel进行转换。
下面一起来看下有哪些新鲜好用的特性吧!
Object.fromEntries
ES2017引入了Object.entries, 这个方法可以将对象转换为数组,如下所示:
let students = {
amelia: 20,
beatrice: 22,
cece: 20,
deirdre: 19,
eloise: 21
}
Object.entries(students)
// [
// [ 'amelia', 20 ],
// [ 'beatrice', 22 ],
// [ 'cece', 20 ],
// [ 'deirdre', 19 ],
// [ 'eloise', 21 ]
// ]
这个功能相当好用,因为它允许对象使用数组原型中内置的众多函数,比如map, filter、reduce等。但是遗憾的是,如果想要把结果再次转化为对象,就需要手动写一些代码来处理。
let students = {
amelia: 20,
beatrice: 22,
cece: 20,
deirdre: 19,
eloise: 21
}
// convert to array in order to make use of .filter() function
let overTwentyOne = Object.entries(students).filter(([name, age]) => {
return age >= 21
}) // [ [ 'beatrice', 22 ], [ 'eloise', 21 ] ]
// turn multidimensional array back into an object
let DrinkingAgeStudents = {}
for (let [name, age] of overTwentyOne) {
DrinkingAgeStudents[name] = age;
}
// { beatrice: 22, eloise: 21 }
Object.fromEntrie正是为解决这种重复工作而设计的,有了它你就可以用更为简洁的代码,在对象使用数组原型的方法了。
let students = {
amelia: 20,
beatrice: 22,
cece: 20,
deirdre: 19,
eloise: 21
}
// convert to array in order to make use of .filter() function
let overTwentyOne = Object.entries(students).filter(([name, age]) => {
return age >= 21
}) // [ [ 'beatrice', 22 ], [ 'eloise', 21 ] ]
// turn multidimensional array back into an object
let DrinkingAgeStudents = Object.fromEntries(overTwentyOne);
// { beatrice: 22, eloise: 21 }
但需要注意的是,数组和对象是不同的数据格式,某些特定的情况下会造成数据丢失,下面的代码中,存在重复key的情况:
let students = [
[ 'amelia', 22 ],
[ 'beatrice', 22 ],
[ 'eloise', 21],
[ 'beatrice', 20 ]
]
let studentObj = Object.fromEntries(students);
// { amelia: 22, beatrice: 20, eloise: 21 }
// dropped firs
因此在使用这个方法时要明确其潜在的副作用。
Object.fromEntries的支持情况
Chrome | Firefox | Safari | Edge |
---|---|---|---|
75 | 67 | 12.1 | -- |
Array.prototype.flat
多维数组是一种常见的数据格式,特别是在进行数据检索的时候。将多维数组打平是个常见的需求。通常我们能够实现,但是不够优雅。
下面的代码,在进行map之后产生了多维数组,我们想要将其打平
let courses = [
{
subject: "math",
numberOfStudents: 3,
waitlistStudents: 2,
students: ['Janet', 'Martha', 'Bob', ['Phil', 'Candace']]
},
{
subject: "english",
numberOfStudents: 2,
students: ['Wilson', 'Taylor']
},
{
subject: "history",
numberOfStudents: 4,
students: ['Edith', 'Jacob', 'Peter', 'Betty']
}
]
let courseStudents = courses.map(course => course.students)
// [
// [ 'Janet', 'Martha', 'Bob', [ 'Phil', 'Candace' ] ],
// [ 'Wilson', 'Taylor' ],
// [ 'Edith', 'Jacob', 'Peter', 'Betty' ]
// ]
[].concat.apply([], courseStudents) // we're stuck doing something like this
下面我们使用Array.prototype.flat进行数组打平,这个方法支持传入打平深度做为参数:
let courseStudents = [
[ 'Janet', 'Martha', 'Bob', [ 'Phil', 'Candace' ] ],
[ 'Wilson', 'Taylor' ],
[ 'Edith', 'Jacob', 'Peter', 'Betty' ]
]
let flattenOneLevel = courseStudents.flat(1)
console.log(flattenOneLevel)
// [
// 'Janet',
// 'Martha',
// 'Bob',
// [ 'Phil', 'Candace' ],
// 'Wilson',
// 'Taylor',
// 'Edith',
// 'Jacob',
// 'Peter',
// 'Betty'
// ]
let flattenTwoLevels = courseStudents.flat(2)
console.log(flattenTwoLevels)
// [
// 'Janet', 'Martha',
// 'Bob', 'Phil',
// 'Candace', 'Wilson',
// 'Taylor', 'Edith',
// 'Jacob', 'Peter',
// 'Betty'
// ]
在不提供参数的时候,默认打平参数是1:
let courseStudents = [
[ 'Janet', 'Martha', 'Bob', [ 'Phil', 'Candace' ] ],
[ 'Wilson', 'Taylor' ],
[ 'Edith', 'Jacob', 'Peter', 'Betty' ]
]
let defaultFlattened = courseStudents.flat()
console.log(defaultFlattened)
// [
// 'Janet',
// 'Martha',
// 'Bob',
// [ 'Phil', 'Candace' ],
// 'Wilson',
// 'Taylor',
// 'Edith',
// 'Jacob',
// 'Peter',
// 'Betty'
// ]
需要注意,上面的示例中,数组并不是被完全打平的。默认情况下,这个方法并不是贪婪方法, 也就是说,如果在不知道数组深度未知的情况下,想要完全打平需要传入Infinity作为参数。
let courseStudents = [
[ 'Janet', 'Martha', 'Bob', [ 'Phil', 'Candace' ] ],
[ 'Wilson', 'Taylor' ],
[ 'Edith', 'Jacob', 'Peter', 'Betty' ]
]
let alwaysFlattened = courseStudents.flat(Infinity)
console.log(alwaysFlattened)
// [
// 'Janet', 'Martha',
// 'Bob', 'Phil',
// 'Candace', 'Wilson',
// 'Taylor', 'Edith',
// 'Jacob', 'Peter',
// 'Betty'
// ]
不过你要小心, 当数组深度完全未知的情况下, 冒然"贪婪"进行数组打平操作可能不是一个很好的选择。
Array.prototype.flat的支持情况
Chrome | Firefox | Safari | Edge |
---|---|---|---|
75 | 67 | 12 | -- |
Chrome Android | Firefox Android | iOS Safari | IE Mobile | Samsung internet | Android Webview |
---|---|---|---|---|---|
75 | 67 | 12.1 | -- | -- | 67 |
Array.prototype.flatMap
有了flat方法,那自然有其兄弟方法Array.prototype.flatMap。看下面一个例子,当我们想要在数组里面插入一些元素,我们原先可能是这么操作的:
let grades = [78, 62, 80, 64]
let curved = grades.map(grade => [grade, grade + 7])
// [ [ 78, 85 ], [ 62, 69 ], [ 80, 87 ], [ 64, 71 ] ]
let flatMapped = [].concat.apply([], curved) // now flatten, could use flat but that didn't exist before either
// [
// 78, 85, 62, 69,
// 80, 87, 64, 71
// ]
使用Array.prototype.flat,我们可以这样实现:
let grades = [78, 62, 80, 64]
let flatMapped = grades.map(grade => [grade, grade + 7]).flat()
// [
// 78, 85, 62, 69,
// 80, 87, 64, 71
// ]
但是这只是个相对比较好的做法,那有人就会想到,如果把它内置到数组原型上岂不更棒?下面我们使用flatmap改写下:
let grades = [78, 62, 80, 64]
let flatMapped = grades.flatMap(grade => [grade, grade + 7]);
// [
// 78, 85, 62, 69,
// 80, 87, 64, 71
// ]
还记得Array.prototype.flat默认情况下只打平一层吗?实际上flatMap是综合了map和flat的操作,所以它也只能打平一层。
let grades = [78, 62, 80, 64]
let flatMapped = grades.flatMap(grade => [grade, [grade + 7]]);
// [
// 78, [ 85 ],
// 62, [ 69 ],
// 80, [ 87 ],
// 64, [ 71 ]
// ]
Array.prototype.flatmap的支持情况
Chrome | Firefox | Safari | Edge |
---|---|---|---|
75 | 67 | 12 | -- |
Chrome Android | Firefox Android | iOS Safari | IE Mobile | Samsung internet | Android Webview |
---|---|---|---|---|---|
75 | 67 | 12.1 | -- | -- | 67 |
String.trimStart 和 String.trimEnd
ES2019中另一个优秀的新特性是为一些字符串方法的取了别名,让其含义更为明确。比如说,以前我们使用的String.trimRight和String.trimLeft
let message = " Welcome to CS 101 "
message.trimRight()
// ' Welcome to CS 101'
message.trimLeft()
// 'Welcome to CS 101 '
message.trimRight().trimLeft()
// 'Welcome to CS 101'
这些方法都很实用,但是为了让其更为符合其语义,即移除开头和结尾的空格,我们改为使用String.trimStart 和 String.trimEnd。
let message = " Welcome to CS 101 "
message.trimEnd()
// ' Welcome to CS 101'
message.trimStart()
// 'Welcome to CS 101 '
message.trimEnd().trimStart()
// 'Welcome to CS 101'
String.trimStart和String.trimEnd的支持情况
Chrome | Firefox | Safari | Edge |
---|---|---|---|
75 | 67 | 12 | -- |
可选的catch绑定
在ES2019中,try-catch语句中的参数变为了一个可选项。以前我们写catch语句时,必须传递一个异常参数。这就意味着,即便我们在catch里面根本不需要用到这个异常参数也必须将其传递进去。
try {
let parsed = JSON.parse(obj)
} catch(e) {
// ignore e, or use
console.log(obj)
}
而现在,如果我们在catch语句里面不使用这个变量时,我们就不用传递它了。
try {
let parsed = JSON.parse(obj)
} catch {
console.log(obj)
}
可选catch绑定的支持情况
Chrome | Firefox | Safari | Edge |
---|---|---|---|
75 | 67 | 12 | -- |
Function.toString() 的改变
ES2019中,Function.toString()发生了变化。从前,执行这个方法时,得到的字符串是去空白符号的:
function greeting() {
const name = 'CSS Tricks'
console.log(`hello from ${name}`)
}
greeting.toString()
//'function greeting() {\nconst name = \'CSS Tricks\'\nconsole.log(`hello from ${name} //`)\n}'
而现在,得到的字符串呈现出原本源码的样子。
function greeting() {
const name = 'CSS Tricks'
console.log(`hello from ${name}`)
}
greeting.toString()
// 'function greeting() {\n' +
// " const name = 'CSS Tricks'\n" +
// ' console.log(`hello from ${name}`)\n' +
// '}'
这简简单单只是一个内部实现方式的改变,但是对于写博客的人来说也许写作从此就会变得轻松很多了。
Function.toString()的支持情况
Chrome | Firefox | Safari | Edge |
---|---|---|---|
75 | 67 | 12(部分) | 17(部分) |
到此为止,就是ES2019新增的主要内容。
下面的这些其他的新增属性,就留给你自己探索吧:
Symbol description(https://github.com/tc39/proposal-Symbol-description)
Sort stability(https://tc39.es/ecma262/#sec-array.prototype.sort)
ECMAScript as JSON superset(https://github.com/tc39/proposal-json-superset)
JSON.stringify(https://github.com/tc39/proposal-well-formed-stringify)
祝写码愉快!
关于奇舞周刊
《奇舞周刊》是360公司专业前端团队「奇舞团」运营的前端技术社区。关注公众号后,直接发送链接到后台即可给我们投稿。