Appearance
21. 使对象具有可迭代性
在 Object.prototype
上添加一个可迭代协议的实现之后,可以使得对象(plain object)具有某些可迭代特性,例如 for (let [k, v] of obj)
遍历:
js
let obj = {
name: 'Tom',
age: 20
}
for (let [k, v] of obj) {
console.log(k, v)
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
1. 使用迭代器实现
js
Object.prototype[Symbol.iterator] = function () {
let arr = []
for (k in this) {
arr.push([k, this[k]])
}
let index = 0
return {
next: () => {
if (index < arr.length) {
return { done: false, value: arr[index++] }
}
return { done: true, value: undefined }
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2. 使用生成器实现
生成器也是一种迭代器,相当于提供了一种更加简洁的写法。
js
Object.prototype[Symbol.iterator] = function* () {
let arr = []
for (k in this) {
arr.push([k, this[k]])
}
yield* arr
}
1
2
3
4
5
6
7
2
3
4
5
6
7
测试:
js
let obj = {
name: 'Tom',
age: 20
}
for (let [k, v] of obj) {
console.log(k, v)
}
/*
* name Tom
* age 20
*/
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
3. 举一反三
举一反三,如何在不修改原代码的情况下,使得第二行代码输出 1 3
?
js
var [a, b] = { a: 1, b: 3 }
console.log(a, b) // 1 3
1
2
2
这里如果是用 {a, b}
来接受就能够执行,因为 JS 对象天生具有解构赋值特性,前提接收的方式前后要一致,但这里前面是数组形式。
JS 中的解构赋值分为两种情况:
- 数组解构赋值(由
Symbol.iteratel
实现) - 对象解构赋值(JS 底层做的特殊实现,对象解构必须使用对象形式接受)
那如何做到对象解构,然后使用数组形式 [a, b]
接受呢?很容易想到可以在 Object 上实现 Symbol.iteratel
方法,使得对象具有类似数组的解构特性。
js
Object.prototype[Symbol.iterator] = function* () {
let arr = []
for (let k in this) {
arr.push(this[k])
}
yield* arr
}
var [a, b] = { a: 1, b: 3 }
console.log(a, b) // 1 3
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
简洁写法:
js
Object.prototype[Symbol.iterator] = function* () {
yield* Object.values(this).map(item => item)
}
1
2
3
2
3