ECMAScript 标准再次更新,在 ES2019 中添加了新功能。现在 已在 Node、Chrome、Firefox 和 Safari 中正式可用,您还可以使用 Babel 将这些功能编译成 JavaScript 的不同版本,如果您需要支持旧版浏览器。
让我们看看有什么新功能吧!
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 ]
// ]
这是一个很棒的补充,因为它允许对象利用 Array 原型中内置的众多函数。例如 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.fromEntries
旨在消除此循环!它为您提供了更简洁的代码,邀请您在对象上使用数组原型方法。
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 }
需要注意的是,数组和对象是不同的数据结构,这是有原因的。在某些情况下,在两者之间切换会导致数据丢失。下面数组元素变为重复对象键的示例就是其中之一。
let students = [
[ 'amelia', 22 ],
[ 'beatrice', 22 ],
[ 'eloise', 21],
[ 'beatrice', 20 ]
]
let studentObj = Object.fromEntries(students);
// { amelia: 22, beatrice: 20, eloise: 21 }
// dropped first beatrice!
使用这些函数时,请务必注意潜在的副作用。
Object.fromEntries 支持情况
Chrome | Firefox | Safari | Edge |
---|---|---|---|
75 | 67 | 12.1 | 不支持 |
🔍 我们需要您的帮助。 您是否可以访问移动浏览器以测试这些和其他功能?请在评论中留下您的结果——我们会查看并将其包含在文章中。
Array.prototype.flat
多维数组是一种非常常见的数据结构,尤其是在检索数据时。扁平化它的能力是必要的。它一直都是可能的,但并不美观。
让我们以以下示例为例,其中我们的映射为我们留下了一个我们想要扁平化的多维数组。
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
的组合函数。我们实际上已经在上面看到了一个这个函数有用处的例子,但让我们再看一个。
如果我们想在数组中插入元素会怎样?在 ES2019 添加之前,它会是什么样子?
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
的默认参数是 1。而 flatMap
等同于组合 map
和 flat
且不带参数。因此,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.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'
这些都是很棒的函数,但是为它们提供更符合其目的的名称也很有益。删除开头空格和结尾空格。
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 | 不支持 |
可选捕获绑定
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)
}
如果您已经知道错误是什么并且正在查找触发它的数据,这是一个很好的选择。
可选捕获绑定支持情况
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 | 60 | 12 – 部分支持 | 17 – 部分支持 |
就是这样!ES2019 的主要功能新增。
还有一些其他新增功能您可能需要探索。其中包括
快乐的 JavaScript 编程!
令人兴奋的东西!
不错。感谢分享。
非常好
太棒了!感谢分享这些很棒的技巧!
很棒的文章。
在你的第一个代码片段中,循环结尾处你混合了可迭代变量,它应该是 overTwentyOne 而不是 DrinkingAgeStudents。
感谢你指出这一点!
for (let [name, age] of DrinkingAgeStudents) { …
应该为
for (let [name, age] of overTwentyOne) {
谢谢!已全部修正 :)
我做了一个 测试页面,以便您可以检查您的浏览器是否支持这些功能。
此外,还提供了一个 屏幕截图,显示它在不同版本的 Firefox 中运行的情况。左侧是 Firefox 70 和 Firefox 3,右侧是 Icecat 60 和 Fennec 68。