ES7 & ES8

在2015年发布的 ECMAScript(ES6)新增内容很多,花费了将近 6 年(2009-11 至 2015-6)的时间才将其标准化。因此,从 ECMAScript 2016(ES7)开始,版本发布变得更加频繁,每年发布一个新版本,新增内容也会更小,基本只需要花费半个小时就能搞懂了。本文将大致介绍ES7,ES8和ES9的新特性,希望对大家日后采用新版本时有所借鉴。

ES7

ECMAScript 2017特性一览:

  • Array.prototype.includes()方法
  • 求幂运算符

Array.prototype.includes

Array.prototype.includes(value:任意值): boolean

如果传入的值在当前数组(this)中则返回 true,否则返回 false:

1
2
3
4
> ['a', 'b', 'c'].includes('a')
true
> ['a', 'b', 'c'].includes('d')
false

includes 方法与 indexOf 方法很相似——下面两个表达式是等价的:

1
2
arr.includes(x)
arr.indexOf(x) >= 0

唯一的区别是 includes() 方法能找到 NaN,而 indexOf() 不行:

1
2
3
4
> [NaN].includes(NaN)
true
> [NaN].indexOf(NaN)
-1

includes 不会区分 +0 和 -0 (这也与其他 JavaScript 特性表现一致):

1
2
> [-0].includes(+0)
true

类型数组也有 includes() 方法:

1
2
let tarr = Uint8Array.of(12, 5, 3);
console.log(tarr.includes(5)); // true

2.指数运算符
新提出来的特性是将 作为指数操作的中缀运算符:`x y`

与以下表达式运算结果相同:Math.pow(x, y)

示例:

1
2
3
4
let squared = 3 ** 2; // 9
let num = 3;
num **= 2;
console.log(num); // 9

ES8

ECMAScript 2017特性一览
主要新功能:

  • 异步函数 Async Functions
  • 共享内存和Atomics

次要新功能:

  • String padding
  • Object.values / Object.entries
  • Object.getOwnPropertyDescriptors
  • 函数参数列表和调用中的尾逗号

String padding

在 String 对象中,ES8 增加了两个新的函数: padStart 和 padEnd 。正如其名,这两个函数的作用就是在字符串的头部和尾部增加新的字符串,并且返回一个具有指定长度的新的字符串。你可以使用指定的字符、字符串或者使用函数提供的默认值-空格来填充源字符串。具体的函数申明如下:

1
2
str.padStart(targetLength [, padString])
str.padEnd(targetLength [, padString])

这俩函数的第一个参数是 targetLength ,这个参数指的是设定这两个函数最后返回的字符串的长度,如果这个参数小于或等于原来字符串的长度时,返回原来的字符串。第二个参数 padString 是可选参数,代表你想要填充的内容,默认值是空格。

具体代码示例如下:

1
2
3
4
5
6
7
8
9
10
'es8'.padStart(2); // 'es8'
'es8'.padStart(5); // ' es8'
'es8'.padStart(6, 'woof'); // 'wooes8'
'es8'.padStart(14, 'wow'); // 'wowwowwowwoes8'
'es8'.padStart(7, '0'); // '0000es8'
'es8'.padEnd(2); // 'es8'
'es8'.padEnd(5); // 'es8 '
'es8'.padEnd(6, 'woof'); // 'es8woo'
'es8'.padEnd(14, 'wow'); // 'es8wowwowwowwo'
'es8'.padEnd(7, '6'); // 'es86666'

Object.values & Object.entries

在 Object 中,新增了两个新的函数,Object.values 函数和 Object.entries 函数。Object.values 函数将会返回一个数组,该数组的内容是函数参数(一个对象)可遍历属性的属性值。数组中得到的属性值的顺序与你在对参数对象使用 for in 语句时获取到的属性值的顺序一致。

具体的代码示例如下:

1
2
3
4
5
6
7
8
9
const obj = { x: 'xxx', y: 1 };
Object.values(obj); // ['xxx', 1]
const obj = ['e', 's', '8']; // same as { 0: 'e', 1: 's', 2: '8' };
Object.values(obj); // ['e', 's', '8']
// when we use numeric keys, the values returned in a numerical
// order according to the keys
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.values(obj); // ['yyy', 'zzz', 'xxx']
Object.values('es8'); // ['e', 's', '8']

Object.entries 函数与 Object.values 函数类似,也是返回一个数组,只不过这个数组是一个以源对象(参数)的可枚举属性的键值对为数组 [key, value] 的 n 行 2 列的数组。它的返回顺序与 Object.values 函数类似。

1
2
3
4
5
6
7
const obj = { x: 'xxx', y: 1 };
Object.entries(obj); // [['x', 'xxx'], ['y', 1]]
const obj = ['e', 's', '8'];
Object.entries(obj); // [['0', 'e'], ['1', 's'], ['2', '8']]
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.entries(obj); // [['1', 'yyy'], ['3', 'zzz'], ['10': 'xxx']]
Object.entries('es8'); // [['0', 'e'], ['1', 's'], ['2', '8']]

getOwnPropertyDescriptors

Object 中还有一个新成员,那就是 Object.getOwnPropertyDescriptors 函数。该函数返回指定对象(参数)的所有自身属性描述符。所谓自身属性描述符就是在对象自身内定义,不是通过原型链继承来的属性。

有两种描述符号类型:

  1. 数据描述符(Data descriptor)
  2. 存取器描述符(Accessor descriptor)

存取描述符有必须的属性:get和set(可以只有get或set),以及可选的属性:configurable和enumerable
该函数返回的每个描述符对象可能会有的 key 值分别是:configurable、enumerable、writable、get、set和value。

示例一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const obj = { 
get es7() { return 777; },
get es8() { return 888; }
};
Object.getOwnPropertyDescriptor(obj);
// {
// es7: {
// configurable: true,
// enumerable: true,
// get: function es7(){}, //the getter function
// set: undefined
// },
// es8: {
// configurable: true,
// enumerable: true,
// get: function es8(){}, //the getter function
// set: undefined
// }
// }

示例二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
> let azatsBooks = { 
books: ['React Quickly'],
get latest() {
let numberOfBooks = this.books.length
if (numberOfBooks == 0) return undefined
return this.books[numberOfBooks - 1]
}
}

> Object.getOwnPropertyDescriptor(azatsBooks, 'books')

Object
configurable: true
enumerable: true
value: Array[1]
writable: true
__proto__: Object

> Object.getOwnPropertyDescriptor(azatsBooks, 'latest')

Object
configurable: truee
numerable: true
get: latest()
set: undefined
__proto__: Object

> console.log(Object.getOwnPropertyDescriptors(azatsBooks))

Object
books: Object
configurable: true
enumerable: true
value: Array[1]
writable: true
__proto__: Object
latest: Object
configurable: true
enumerable: true
get: latest()
set: undefined
__proto__: Object
__proto__: Object

在ES5中,开发者要使用Object.assign()来拷贝对象, Object.assign()分配属性只有copy和定义新的属性。当我们使用更加复杂对象和类原型,这可能会出问题。
Object.getOwnPropertyDescriptors允许创建真实的对象浅副本并创建子类,它通过给开发者描述符来做到这一点.在Object.create(prototype, object)放入描述符后,返回一个真正的浅拷贝

1
2
3
4
Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
)

或者你可以合并两个对象target和source如下:

1
2
3
4
Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(source)
)

函数参数列表结尾允许逗号

在函数参数列表中最后一个参数之后的逗号以及函数调用时最后一个参数之后的逗号。ES8允许在函数定义或者函数调用时,最后一个参数之后存在一个结尾逗号而不报 SyntaxError 的错误。
示例代码如下:

1
2
3
4
5
6
7
函数声明时
function es8(var1, var2, var3,) {
// ...
}

函数调用时
es8(10, 20, 30,);ES8的这项新特性受启发于对象或者数组中最后一项内容之后的逗号,如 [10, 20, 30,] 和 { x: 1, } 。

异步函数

由 async 关键字定义的函数声明定义了一个可以异步执行的函数,它返回一个 AsyncFunction 类型的对象。异步函数的内在运行机制和 Generator 函数非常类似,但是不能转化为 Generator 函数。

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 声明
function fetchTextByPromise() {
return new Promise(resolve => {
setTimeout(() => {
resolve("es8");
}, 2000);
});
}

async function sayHello() {
const externalFetchedText = await fetchTextByPromise();
console.log(`Hello, ${externalFetchedText}`); // Hello, es8
}

// 调用
console.log(1);
sayHello();
console.log(2);

// 输出
1 // immediately
2 // immediately
Hello, es8 // after 2 seconds