ES6_迭代器和生成器(九)

迭代器

看例子~~

1
2
3
4
5
6
7
8
9
10
11
let version = 0
function 发布(){
version++;
return version;
}

发布() // 1
发布() // 2
发布() // 3
发布() // 4
发布() // 5
  • 第一次升级
1
2
3
4
5
6
7
8
function 发布器(){
return {
next:undefined
}
}

let a = 发布器();
a.next // undefined
  • 第二次升级,补充next
1
2
3
4
5
6
7
8
function 发布器(){
return {
next:function(){}
}
}

let a = 发布器();
a.next // 是个函数
  • 第三次升级: next的函数返回一个对象
1
2
3
4
5
6
7
8
9
10
11
12
13
function 发布器(){
return {
next:function(){
return {
value:1
}
}
}
}

let a = 发布器();
a.next // 是个函数
a.next() // 返回对象 {value:1}
  • 第四次升级: 发布器内部有一个初始变量,在 next调用的时候 自增
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function 发布器(){
let _value = 0;
return {
next:function(){
_value++;
return {
value:_value
}
}
}
}

let a = 发布器();
a.next // 是个函数

a.next() // 返回对象 {value:1}
a.next() // 返回对象 {value:2}
a.next() // 返回对象 {value:3}
  • 第五次升级: 发布器内部有done 标志,和边界条件max
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
function 发布器(){
let _value = 0;
let max = 5;
return {
next:function(){
_value++;
if(_value > max){
throw new Error('你突破了天际,已经撞墙了!')
}
if(_value === max){
return {
value:_value,
done:true
}
}
return {
value:_value,
done:false
}
}
}
}

let a = 发布器();
a.next // 是个函数

a.next() // 返回对象 {value:1}
a.next() // 返回对象 {value:2}
a.next() // 返回对象 {value:3}
a.next() // 返回对象 {value:4}
a.next() // 返回对象 {value:5}
a.next() // 报错 Uncaught Error: 你突破了天际,已经撞墙了!

这就是迭代器

迭代器

  • 它有一个next方法,并返回一个 对象形如 {value:你的value,done:false}

生成器:迭代器的语法糖

写法

1
2
3
function 后加一个 "*"

function内部定义 yield
  • 在看我们的代码
1
2
3
4
5
6
7
8
9
10
11
function * 发布器(){
var version = 0;
while(true){
version++;
yield version;
}
}
var a = 发布器();
a.next() // {value: 1, done: false}
a.next() // {value: 2, done: false}
// ... 由于是 while(true), 你可以一致 a.next() 到世界尽头

解析代码

1
2
var a = 发布器(); // 代码运行到  version++ , yield之前
a.next() // 第一次next,把结果吼出来 {value: 1, done: false} ,同时再次进入while 运行到 version++;再次停到 yield之前

for …of

  • 针对数组
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

// 这个是迭代
for(let item of [3,2,1]){
console.log(item)
}
// 打印 3,2,1


// 这个是遍历
for(let item in [3,2,1]){
console.log(item)
}
// 打印 0 ,1,2

// 数组添加额外属性!!!

var c = [3,2,1]
c.x = 'y'
// 这个是遍历
for(let item in c){console.log(item)}
// 打印 0,1,2,x

// 这个是迭代
for(let item of c){console.log(item)}
// 打印 3 ,2,1

再看object

1
2
3
4
5
6
var d = {a:1,b:2,c:3}
// 这个是遍历
for(let i in d){console.log(i)} // 打印的是key: a,b,c

// 这个是迭代
for(let i of d){console.log(i)} // 报错 d is not iterable

区分 for in 和 for of

  • for in 是旧语法
    • 无论数组还是对象都可以 “遍历”
  • for of 是新语法

    • 数组可以迭代
    • 对象是不可迭代的
  • 数组和对象都能 “遍历” for in

  • 数组能 “迭代” 对象 不能 “迭代”

什么样的东西能迭代呢?

  • 数组
  • 符合某些特征的东西 含有 obj[Symbol.iterator] 它就是一个可迭代的
1
2
3
4
5
let arr = []
arr[Symbol.iterator] // 返回一个函数

let obj = {}
obj[Symbol.iterator] // undefined

让对象可迭代

1
2
3
4
5
6
7
8
9
10
11
let obj = {a:'aa',b:'bb',c:'cc'}
obj[Symbol.iterator] // undefined

// 让对象支持迭代
obj[Symbol.iterator] = function*(){
let keys = Object.keys(obj)
for(let i=0;i<keys.length;i++){
yield obj[keys[i]]
}
}
for(let i of obj){console.log(i)} // aa bb cc

为啥数组可以迭代,对象不行?

因为数组知道如何按顺序访问,但是对象不知道取key的顺序是不确定的

Symbol.iterator 是啥?

  • 它是一个 Symbol
  • 它是一个独一无二的值
  • 它就是为了实现迭代器,实现可迭代对象

假如没有 Symbol

1
2
3
4
5
// 难道我们要这样?
object['__iterator__'] // 这样好吗? ,会不会冲突,会不会和现存的内容覆盖?
// 如果用Symbol呢?
这样跟谁都没有关系
object[Symbol.iterator]