查看原文
其他

ES2019新特性你知道哪些?

刘冰晶 奇舞精选 2021-01-15

编者按:本文译者奇舞团前端开发工程师刘冰晶。

随着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, filterreduce等。但是遗憾的是,如果想要把结果再次转化为对象,就需要手动写一些代码来处理。

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的支持情况

ChromeFirefoxSafariEdge
756712.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的支持情况

ChromeFirefoxSafariEdge
756712--
Chrome AndroidFirefox AndroidiOS SafariIE MobileSamsung internetAndroid Webview
756712.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是综合了mapflat的操作,所以它也只能打平一层。

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的支持情况

ChromeFirefoxSafariEdge
756712--
Chrome AndroidFirefox AndroidiOS SafariIE MobileSamsung internetAndroid Webview
756712.1----67

String.trimStart 和 String.trimEnd

ES2019中另一个优秀的新特性是为一些字符串方法的取了别名,让其含义更为明确。比如说,以前我们使用的String.trimRightString.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.trimStartString.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.trimStartString.trimEnd的支持情况

ChromeFirefoxSafariEdge
756712--

可选的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绑定的支持情况

ChromeFirefoxSafariEdge
756712--

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()的支持情况

ChromeFirefoxSafariEdge
756712(部分)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公司专业前端团队「奇舞团」运营的前端技术社区。关注公众号后,直接发送链接到后台即可给我们投稿。


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存