这里有ECMAScript 2016,2017和2018 最新特性的例子

2018-05-24

文章并非通篇翻译,而是进行了摘要,有兴趣的小伙伴建议直接阅读原文,有什么好的建议,或者不对的地方,欢迎留言或者@我

原文链接:https://medium.freecodecamp.org/here-are-examples-of-everything-new-in-ecmascript-2016-2017-and-2018-d52fa3b5a70e


下文包含了18个 TC39 已完成提案的特性

ECMAScript 2016

Array.prototype.includes

数组的 includes 方法可以非常简单的判断谋项是否存在于数组中,包括 NaN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const arr = [1, 2, 3, 4, NaN]

// 使用 indexOf 的情况
if (arr.indexOf(3) >= 0) {
console.log(true)
}

// 使用 includes
if (arr.includes(3)) {
console.log(true)
}

// PS: indexOf 无法搜索 NaN
arr.includes(NaN) // true
arr.indexOf(NaN) // -1

幂中缀运算符(Exponentiation infix operator)

类似 ++ --,使用 ** 可以快速进行幂运算

1
2
3
4
5
// 使用 Math.pow
Math.pow(7, 2) // 49

// 使用 **
7**2 // 49

ECMAScript 2017

Object.values()

可以用于获取 Object 的值,类似 Object.keys() 用于获取 Object 中的 key

1
2
3
4
5
6
7
8
9
10
11
const cars = { BMW: 3, Tesla: 2, Toyota: 1 }

// 使用 Object.keys() 加上 map 的方式获取值
const vals = Object.keys(cars).map(key => cars[key])

console.log(vals) // [3, 2, 1]

// 使用 Object.values()
const values = Object.values(cars)

console.log(values) // [3, 2, 1]

Object.entries()

将对象的 key 和 value 变为数组的形式,便于对象的遍历或者将 Object 转换为 Map

1
2
3
4
5
6
7
8
9
10
11
12

// 使用效果
const cars = { BMW: 3, Tesla: 2, Toyota: 1 }

const entries = Object.entries(cars)

console.log(entries) // [ ['BMW', 3], ['Tesla', 2], ['Toyota', 1] ]

// 将 Object 转化为 Map
const cars = { BMW: 3, Tesla: 2, Toyota: 1 }

const map1 = new Map(Object.entries(cars))

关于 Map 相关的资料点击这里

字符串填充(String padding)

可以使用 String.prototype.padStartString.prototype.padEnd 来填充字符串

1
2
3
4
5
6
// 其中第一个参数代表字符串的最终的长度,第二个参数表示需要填充的内容
// 从头开始填充
'5'.padStart(10, '*') // '*********5'

// 从尾开始填充
'5'.padEnd(10, '*') // '5*********'

Object.getOwnPropertyDescriptors

用于返某个 Object 的所有细节包括(get,set)
可以通过 Object 的浅拷贝(Object.assign)和深拷贝(Object.defineProperties)来验证

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
var Car = {
name: 'BMW',
price: 1000000,
set discount(x) {
this.d = x;
},
get discount() {
return this.d;
}
}

console.log(Object.getOwnPropertyDescriptor(Car, 'discount'));
// {
// get: [Function: get],
// set: [Function: set],
// enumerable: true,
// configurable: true
// }

// Object.assign
const ElectricCar = Object.assign({}, Car)
console.log(Object.getOwnPropertyDescriptor(ElectricCar, 'discount'))
// {
// value: undefined,
// writable: true,
// enumerable: true,
// configurable: true
// }

// Object.defineProperties
const ElectricCar2 = Object.defineProperties({}, Object.getOwnPropertyDescriptors(Car))
console.log(Object.getOwnPropertyDescriptor(ElectricCar2, 'discount'))
// { get: [Function: get], 👈🏼👈🏼👈🏼
// set: [Function: set], 👈🏼👈🏼👈🏼
// enumerable: true,
// configurable: true
// }

函数参数后面加逗号(Add trailing commas in the function parameters)

这样的原因是为了类似使用 git 这类的工具时,只有新增的行发生变化(可能和代码风格有关)

Async/Await

这个应该都比较熟悉了,直接上例子

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
function getUser() {
return new Promise(resolve => {
setTimeout(() => {
resolve('join')
}, 1000)
})
}

function getBankBalance() {
return new Promise(resolve => {
setTimeout(() => {
resolve('$1,000')
}, 2000)
})
}

// 使用 async/await 之前
function getAmount() {
getUser()
.then(getBankBalance)
.then(amount => {
console.log(amount)
})
}

// 使用 async/await 之后
async function getAmount2() {
var user = await getUser()
var amount = await getBankBalnce(user);
console.log(amount)
}
  • Async 函数自身返回的是一个 Promise 所以可以使用 .then 方法
  • async/await 并行使用 Promise.all
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function doulieAfterSec() {
    return new Promise(resolve => {
    setTimeout(resolve(2), 1000)
    })
    }

    async function doubleAdded() {
    [a, b] = await Promise.all(doulieAfterSec(), doulieAfterSec())
    }

ECMAScript 2018

共享内存和 atomics (shared memory and atomics)

一个比较高级的特性,还是自行查看作者给出的文章吧

模板字符串限制被移除(Tagged Template literal restriction removed)

在 ES2016 和 ES2016 规范中,模板字符串不允许使用的转义字符,类似\u,\x

但是在 ES2018,放宽了这个要求,允许出现这些字符串,你可以定义一个 Object,里面有 cooked 这个属性(也可以是任意一个属性),来表示 “undefined”,然后再定义一个 raw 属性(也可以是任意你想要的名字),将这些 \u,\x 字符存储在 raw

1
2
3
4
5
6
7
8
function myTagFunc(str) { 
console.log(str) // [undefined, raw: [['hi \ubla123abla']]]
return { "cooked": "undefined", "raw": str.raw[0] }
}

var str = myTagFunc `hi \ubla123abla`

str // { cooked: "undefined", raw: "hi \ubla123abla" }

正则表达式的“dotall”符号(”dotall” flag for Regular exporession)

在正则表达式中,.符号允许匹配任意字符,但是不匹配换行字符,类似 \n`\r\f等 但是在 ES2018 中,增加了/first.second/s中的/s标志位来表示.`来支持匹配换行字符

1
2
3
4
5
// 在不支持之前
/first.second/.test('first\nsecond'); //false

// 在 ES2018 中
/first.second/s.test('first\nsecond'); //true

正则表达式的命名分组捕获(RegExp Named Group Captures)

提供了类似 Python、Java 等语言中的命名分组(当年用 Python 写爬虫的时候相当好用),语法格式为 (?<name>...)

1
2
3
4
5
6
7
8
9
10
// 原先的命名分组
let re1 = /(\d{4})-(\d{2})-(\d{2})/
let result1 = re1.exec('2015-01-02')
console.log(result1) // ['2015-01-02', '2015', '01', '02', index: 0, input: '2015-01-02', groups: undefined]

// 使用命名分组后
let re2 = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
let result2 = re2.exec('2015-01-02')
console.log(result2) // ['2015-01-02', '2015', '01', '02', index: 0, input: '2015-01-02', groups: { year: '2015', month: '01', day: '02'}]
console.log(result2.groups.year) // 2015

可以使用 \k<group name> 在同一个表达式中表示相同分组

1
2
3
4
let sameWords = /(?<fruit>apple|orange)==\k<fruit>/u;

sameWords.test('apple==apple') // true
sameWords.test('apple==orange') // false

字符串中的命名分组使用

1
2
3
4
// 将 "firstName lastName" 替换为 "lastName, firstName"
let re = /(?<firstName>[A-Za-z]+) (?<lastName>[A-Za-z]+$)/u

'Raja Rao'.replace(re, '$<lastName>, $<firstName>') // "Rao, Raja"

Rest properties for Objects

使用 ... 操作符可以将 Object 的剩余未指定的属性进行赋值

1
2
3
4
5
6
7
8
9
10
11
12
let { firstName, age, ...remaining } = {
firstName: 'john',
lasttName: 'smith',
age: 20,
height: '5.10',
race: 'martian'
}

firstName // john
age // 20

remaining // { lasttName: 'smith', age: 20, height: '5.10', race: 'martian' }

可以用来移除不想要的项

1
2
3
4
5
6
7
8
9
10
let { firstName, age, ...cleanObj } = {
firstName: 'john',
lasttName: 'smith',
age: 20,
height: '5.10',
race: 'martian'
}

// cleanObj 就是你真正想要的属性
cleanObj // { lasttName: 'smith', age: 20, height: '5.10', race: 'martian' }

Spread properties for Objects

... 也可用于合并旧对象创建新对象

1
2
3
4
5
6
const person = { fName: 'john' }
const account = { amount: '$1000' }

const personAndAccount = { ...person, ...account }

personAndAccount // { fName: 'john', amount: '$1000' }

正则表达式的回溯断言(RegExp Lookbehind Assertions)

可以(?<=...)获取以某个特定标识之后的内容,(?<!...)获取非某个特定标识之后的内容

1
2
3
4

'#winning'.match(/(?<=#).*/)[0] // 'winning'

'A gallon of milk is $3.00'.match(/(?<!\$).*/) // null

正则表达式的 Unicode 转义字符(RegExp Unicode Property Escapes)

如题,更多内容可以点击查看

1
2
3
4
5
6
//The following matches multiple hindi character
/^\p{Script=Devanagari}+$/u.test('हिन्दी'); //true
//PS:there are 3 hindi characters h

//The following matches a single Greek character
/\p{Script_Extensions=Greek}/u.test('π'); // true

Promise.prototype.finally()

Promise 增加了一个 finally() 方法,顾名思义,不管是 reslove 还是 reject,最终都会执行

1
2
3
4
5
6
7
8
9
10
11
12
let myPromise = new Promise((resolve, reject) => {
throw new Error('wrong')
})
.then(val => {
console.log(val)
})
.catch(e => {
throw new Error('wrong')
})
.finally(() => {
console.log('这里始终会被执行')
})

异步迭代(Asynchronous Iteration)

顾名思义,一个支持包含异步的迭代 for-await-of

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const promises = [
new Promise(resolve => resolve(1)),
new Promise(resolve => resolve(2)),
new Promise(resolve => resolve(3))
]

// 不支持的情况
async function test1() {
for (const obj of promises) {
console.log(obj) // 显示 3 个 Promise 对象
}
}

// 使用 for-await-of
async function test2() {
for await(const obj of promises) {
console.log(obj) // 显示 1,2,3
}
}

test1() // Promise, Promise, Promise
test2()// 1, 2, 3 ...

原文链接:https://medium.freecodecamp.org/here-are-examples-of-everything-new-in-ecmascript-2016-2017-and-2018-d52fa3b5a70e

下面是我的微信

欢迎骚扰

ww1o01