ES2017 是 ECMAScript 的第 8 个版本,正式名称应该叫做 ECMAScript2017,发布于 2017 年 6 月,相比于 ES2015 来讲 ES2017 也只是一个小版本更新,但是同时也带来了很多有用的新功能。
首先是为 Object
对象新增了 values()
方法,这个方法和 ECMAScript5 当中的 keys()
方法非常类似,keys()
方法返回的是对象中所有键所组成的数组,values()
方法返回的是对象中所有值所组成的数组。如下代码所示:
const obj = {
foo: 'value1',
bar: 'value2'
}
console.log(Object.values(obj))
上述代码的运行结果如下:
[ 'value1', 'value2' ]
其次是为 Object
对象新增了 entries()
方法,这个方法是以数组的方式返回对象中所有的键值对。如下代码所示:
const obj = {
foo: 'value1',
bar: 'value2'
}
console.log(Object.entries(obj))
上述代码的运行结果如下:
[ [ 'foo', 'value1' ], [ 'bar', 'value2' ] ]
这使得可以直接使用 for...of
循环遍历普通对象,如下代码所示:
const obj = {
foo: 'value1',
bar: 'value2'
}
for (const [key, value] of Object.entries(obj)) {
console.log(key, value)
}
上述代码的运行结果如下:
foo value1
bar value2
除此以外,因为 Map
的构造函数需要的就是这种格式的数组,这样就可以借助于 entries()
方法将一个对象转换成一个 Map
类型的对象。如下代码所示:
const obj = {
foo: 'value1',
bar: 'value2'
}
console.log(new Map(Object.entries(obj)))
上述代码的运行结果如下:
Map(2) {
'foo' => 'value1', 'bar' => 'value2' }
再有是为 Object
对象新增了 getOwnPropertyDescriptors()
方法,这个方法实际上是用来获取对象当中属性的完整描述信息。自从 ECMAScript5 之后就可以为对象定义 getter
或者 setter
属性,这种 getter
或者 setter
属性是不能够通过 Object.assign()
方法完全复制的。如下代码所示:
var p1 = {
firstName: 'King',
lastName: 'J',
get fullName() {
return this.firstName + this.lastName
}
}
console.log(p1.fullName)
上述代码中定义了一个 getter
属性叫做 fullName
,相当于向外部提供了一个只读属性。其打印结果如下:
KingJ
然后通过 Object.assign()
方法复制一个新对象,并且修改一下这个新对象的 firstName
属性值。如下代码所示:
const p2 = Object.assign({
}, p1)
p2.firstName = 'Dragon'
console.log(p2.fullName)
上述代码的运行结果如下:
KingJ
正常来讲,这时的新对象的 fullName
属性值应该是 DragonJ
,但实际上是 KingJ
。这是因为 Object.assign()
方法在复制对象时将 fullName
属性当做是普通的属性进行复制了,所以说才会出现这种情况。
在这种情况下,就可以使用 Object.getOwnPropertyDescriptors()
方法获取对象当中属性的完整描述信息。如下代码所示:
const descriptors = Object.getOwnPropertyDescriptors(p1)
console.log(descriptors)
上述代码的运行结果如下:
{
firstName: {
value: 'King',
writable: true,
enumerable: true,
configurable: true
},
lastName: {
value: 'J', writable: true, enumerable: true, configurable: true },
fullName: {
get: [Function: get fullName],
set: undefined,
enumerable: true,
configurable: true
}
}
然后再使用 Object.defineProperties()
方法将这个描述信息定义到一个新的对象当中,如下代码所示:
const p2 = Object.defineProperties({
}, descriptors)
p2.firstName = 'Dragon'
console.log(p2.fullName)
上述代码的运行结果如下:
DragonJ
从打印的结果可以看到,这样的话就可以做到对 getter
或者 setter
属性进行复制。
另外,ECMAScript2017 还新增了两个字符串填充方法,分别是 padStart()
方法和 padEnd()
方法。比如使用 for…of 循环遍历一个对象的话,如果直接遍历的结果打印会比较乱。如下代码所示:
const books = {
html: 5,
css: 16,
javascript: 128
}
for (const [name, count] of Object.entries(books)) {
console.log(name, count)
}
上述代码的运行结果如下:
html 5
css 16
javascript 128
这时就可以使用 padStart()
方法和 padEnd()
方法将这些字符串进行对齐操作。如下代码所示:
const books = {
html: 5,
css: 16,
javascript: 128
}
for (const [name, count] of Object.entries(books)) {
console.log(`${
name.padEnd(16, '-')}|${
count.toString().padStart(3, '0')}`)
}
上述代码的运行结果如下:
html------------|005
css-------------|016
javascript------|128
这两个方法的效果总结一下,就是使用给定的字符串去填充指定字符串的开始或结束的位置,直到这个字符串达到指定长度为止。
最后,就是 ECMAScript2017 还有一个非常小的新功能,就是允许在函数的参数列表最后添加尾逗号。这和在定义数组或者对象时,在列表的末尾添加逗号实际上是一样的。
比如定义一个数组,并且在最后一个成员添加尾逗号的话,是否添加尾逗号在执行层面实际上是没有任何区别的,但是很多人还是比较喜欢这种方式。这样使用的好处有两个,一个是如果想重新排列成员的顺序非常容易,一个是如果新增一个成员的话只需要再新建一行。
ECMAScript2017 只不过允许在函数的参数列表中使用这种尾逗号的方式而已。