对象解构

移除不想要的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 移除 _internal 和 tooBig 这两个属性
let {
_internal,
tooBig,
...cleanObject
} = {
_internal: "secret",
tooBig: {},
el1: '1',
el2: '2',
el3: '3'
}

console.log(cleanObject) // { el1: '1', el2: '2', el3: '3' }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let obj = {
name: 'peter',
gender: 'male',
other: {
age: '28',
height: '180',
weight: '160'
}
}

const { other: { age, ...rest2 }, ...rest1 } = obj
const person = {
...rest1,
...rest2,
age: Number(age)
}

console.log(rest1) // { name: 'peter', gender: 'male' }
console.log(rest2) // { height: '180', weight: '160' }
console.log(person) // { name: 'peter', gender: 'male', height: '180', weight: '160', age: 28 }

在函数参数中使用嵌套对象解构

在这个例子中 engine 是一个嵌套在 car 里面的对象,如果我们只需要 engine 里面的属性 vin 我们可以这样做。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const car = {
model: 'bmw 2018',
engine: {
v6: true,
turbo: true,
vin: 12345
}
}

const modelAndVIN = ({ model, engine: { vin } }) => {
console.log(`model: ${model} vin: ${vin}`)
}

modelAndVIN(car) // model: bmw 2018 vin: 12345

合并对象

扩展运算符…

1
2
3
let object1 = { a:1, b:2,c:3 }
let object2 = { b:30, c:40, d:50 }
let merged = { …object1, …object2 } //spread and re-add into merged

根据条件添加对象属性

你不再需要根据条件创建两个不同的对象,以使其具有特定属性。扩展操作符将是一个完美的选择

1
2
3
4
5
6
7
8
9
10
11
12
13
const getUser = (emailIncluded) => {
return {
name: 'John',
surname: 'Doe',
...(emailIncluded ? { email : 'john@doe.com' } : null)
}
}

const user = getUser(true)
console.log(user); // 输出 { name: "John", surname: "Doe", email: "john@doe.com" }

const userWithoutEmail = getUser(false)
console.log(userWithoutEmail) // 输出 { name: "John", surname: "Doe" }

解构原始数据

你曾经有处理过拥有非常多属性的对象吗?我相信你一定有过。可能最常见的情况是我们有一个用户对象,它包含了所有的数据和细节。这里,我们可以调用新的 ES 解构方法来处理这个大麻烦。让我们看看下面的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const rawUser = {
name: 'John',
surname: 'Doe',
email: 'john@doe.com',
displayName: 'SuperCoolJohn',
joined: '2016-05-05',
image: 'path-to-the-image',
followers: 45
...
}

let user = {}, userDetails = {};
({ name: user.name, surname: user.surname, ...userDetails } = rawUser);

console.log(user) // 输出 { name: "John", surname: "Doe" }
console.log(userDetails) // 输出 { email: "john@doe.com", displayName: "SuperCoolJohn", joined: "2016-05-05", image: "path-to-the-image", followers: 45 }

合并对象数组

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
// 将对象数组合并成一个对象
const cities = [
{ name: 'Paris', visited: 'no' },
{ name: 'Lyon', visited: 'no' },
{ name: 'Marseille', visited: 'yes' },
{ name: 'Rome', visited: 'yes' },
{ name: 'Milan', visited: 'no' },
{ name: 'Palermo', visited: 'yes' },
{ name: 'Genoa', visited: 'yes' },
{ name: 'Berlin', visited: 'no' },
{ name: 'Hamburg', visited: 'yes' },
{ name: 'New York', visited: 'yes' }
]

const result = cities.reduce((accumulator, item) => {
return {
...accumulator,
[item.name]: item.visited
}
}, {})

console.log(result)
/* 输出
{
Berlin: "no"
Genoa: "yes"
Hamburg: "yes"
Lyon: "no"
Marseille: "yes"
Milan: "no"
New York: "yes"
Palermo: "yes"
Paris: "no"
Rome: "yes"
}
*/

数组映射

不使用 Array.map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const cities = [
{ name: 'Paris', visited: 'no' },
{ name: 'Lyon', visited: 'no' },
{ name: 'Marseille', visited: 'yes' },
{ name: 'Rome', visited: 'yes' },
{ name: 'Milan', visited: 'no' },
{ name: 'Palermo', visited: 'yes' },
{ name: 'Genoa', visited: 'yes' },
{ name: 'Berlin', visited: 'no' },
{ name: 'Hamburg', visited: 'yes' },
{ name: 'New York', visited: 'yes' }
]

const cityNames = Array.from(cities, ({ name}) => name)
console.log(cityNames)
// 输出 ["Paris", "Lyon", "Marseille", "Rome", "Milan", "Palermo", "Genoa", "Berlin", "Hamburg", "New York"]

数组的解构

交换2个值

1
2
3
4
const [post, comments] = Promise.all([
fetch('/post'),
fetch('/comments')
])

使用 Array 的方法

可以通过 (…) 扩展运算符将 Set 转换成 Array 这样我们就可以在 Set 使用所有 Array 的方法了。

1
2
let mySet = newSet([1,2, 3, 4, 5])
const filtered = [...mySet].filter((x) => x > 3) // [4, 5]

Set

使用 set 来对数组去重

1
2
3
let arr = [1, 1, 2, 2, 3, 3]
let deduped = [...new Set(arr)] // [1, 2, 3]
let deduped = Array.from(new Set(arr))

Map

使用对象初始化 Map 实例

1
2
3
4
5
let obj = { a: 1, b: 1, c: 1 }
map = new Map(Object.entries(obj))
console.log(map.get('a')) // 1
console.log(map.get('b'))
console.log(map.get('c'))

模板字符串

如果这样做的话:

1
2
const string = `First
Second`

那么它会创建出像下面的字符串:

1
2
First
Second

有一个简单的方法可以修复这个问题,只需要将第一行置为空,然后添加了右边的翻译好后调用一个 trim() 方法,就可以消除第一个字符前的所有空格:

1
2
3
const string = `
First
Second`.trim()

对象方法

Object.is() 确定两个值是不是同一个

1
Object.is(a, b)

扩展运算符

用在字符串上的时候,展开操作符会以字符串中的每一个字符创建一个数组:

1
2
const hey = 'hey'
const arrayized = [...hey] // ['h', 'e', 'y']

不定参数

在之前的语法规范中,你只能通过fn.apply(null, arr)的方式来实现,但是这种方式不是很友好和易读。

1
2
const arr = [1, 3, 0, -1, 20, 100]
Math.max.apply(null, arr) // 100
1
2
3
4
5
const array = [1, 2, 3, 4, 5]
function fn() {
console.log(arguments)
}
fn.apply(null, array) // Arguments(5) [0: 1, 1: 2, 2: 3, 3: 4, 4: 5]

现在,剩余参数(rest element)在和数组解构(array destructuring)搭配使用来实现。

1
2
3
4
5
6
const array = [1, 2, 3, 4, 5]
const fn = (foo, bar, ...rest) => {
console.log(rest)
console.log(...arguments)
}
fn(...array) // [3, 4, 5]

箭头函数没有 arguments

1
2
3
4
5
const array = [1, 2, 3, 4, 5]
function fn() {
console.log(...arguments)
}
fn(...array) // 1 2 3 4 5

Generator

一个解释generator如何工作的例子:

1
2
3
4
5
function *calculator(input) {
var doubleThat = 2 * (yield (input / 2))
var another = yield (doubleThat)
return (input * doubleThat * another)
}

我们先初始化它:``

1
const calc = calculator(10)

然后我们在generator中开始进行iterator迭代:

1
2
3
4
5
6
7
calc.next()

//
{
done: false,
value: 5
}

具体过程如下:代码运行了函数,并把input=10传入到生成器构造函数中,该函数一直运行直到抵达 yield,并返回 yield 输出的内容: input / 2 = 5,因此,我们得到的值为5,并告知迭代器还没有 done (函数只是暂停了)。

在第二个迭代处,我们输入7:

1
2
3
4
{
done: false
value: 14
}

7被作为 doubleThat 的值,注意:你可能会把input/2作为输入参数,但这只是第一次迭代的返回值。现在我们忽略它,使用新的输入值7,并将其乘以2。
然后,我们得到第二个 yield 的值,它返回 doubleThat,因此返回值为14。

之后,也是最后一个迭代器,我们输入100:

1
2
3
4
5
6
7
calc.next(100)

//
{
done: true
value: 14000
}

当迭代器完成时(没有更多的 yield 关键字),我们返回 input doubleThat another,这相当于10 * 14 * 100