Skip to content

Latest commit

 

History

History
412 lines (314 loc) · 10.2 KB

20190826_betseyliu_ES2019新特性你知道哪些.md

File metadata and controls

412 lines (314 loc) · 10.2 KB

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

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是综合了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的支持情况

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.trimRightString.trimLeft

let message = "   Welcome to CS 101    "
message.trimRight()
// '   Welcome to CS 101'
message.trimLeft()
// 'Welcome to CS 101   '
message.trimRight().tr

这些方法都很实用,但是为了让其更为符合其语义,即移除开头和结尾的空格,我们改为使用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的支持情况

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新增的主要内容。

下面的这些其他的新增属性,就留给你自己探索吧:

祝写码愉快!