概述
迭代器.Iterator 和 for...of 循环
- 1.Iterator(遍历器)的概念
- 2默认 Iterator 接口
- 3.for...of 循环
1.Iterator(遍历器)的概念
JavaScript 原有的表示“集合”的数据结构
,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator 的作用有三个:
- 为各种数据结构,提供一个统一的、简便的访问接口;
- 使得数据结构的成员能够按某种次序排列;
- ES6 创造了一种新的遍历命令for…of循环,I
terator 接口主要供for...of消费。
Iterator 的遍历过程是这样的
- 创建一个指针对象,
指向当前数据结构的起始位置
。也就是说,遍历器对象本质上,就是一个指针对象。 - 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
- 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
- 不断调用指针对象的next方法,直到它指向数据结构的结束位置。
每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含
value和done两个属性的对象
。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
2默认 Iterator 接口
Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for…of循环(详见下文)。当使用for…of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。
一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性
,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。Symbol.iterator属性本身是一个函数
,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内
。
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}
};
对象obj是可遍历的(iterable),因为具有Symbol.iterator属性。执行这个属性,会返回一个遍历器对象
。该对象的根本特征就是具有next方法
。每次调用next方法,都会返回一个代表当前成员的信息对象,具有value和done两个属性。
ES6 的有些数据结构原生具备 Iterator 接口
(比如数组),即不用任何处理,就可以被for…of循环遍历。
1 | 2 | 3 | 4 |
---|---|---|---|
Array | Map | Set | Map |
String | TypedArray | 函数的 arguments 对象 | NodeList 对象 |
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
上面代码中,变量arr
是一个数组,原生就具有遍历器接口,部署在arr的Symbol.iterator属性上面。所以,调用这个属性,就得到遍历器对象
。
对于原生部署 Iterator 接口的数据结构,不用自己写遍历器生成函数,for…of循环会自动遍历它们。除此之外,其他数据结构(主要是对象)的 Iterator 接口,都需要自己在Symbol.iterator属性上面部署,这样才会被for…of循环遍历。
一个对象如果要具备可被for...of
循环调用的 Iterator 接口,就必须在Symbol.iterator的属性上部署遍历器生成方法(原型链上的对象具有该方法也可)。
let obj = {
data: [ 'hello', 'world' ],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
};
}
return { value: undefined, done: true };
}
};
}
};
3.for…of 循环
一个数据结构只要部署了Symbol.iterator
属性,就被视为具有 iterator 接口,就可以用for...of循环遍历它的成员
。也就是说,for…of循环内部调用的是数据结构的Symbol.iterator方法。
for...of循环
可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments
对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。
数组原生具备iterator接口
(即默认部署了Symbol.iterator属性),for…of循环本质上就是调用这个接口产生的遍历器,可以用下面的代码证明。
const arr = ['red', 'green', 'blue'];
for(let v of arr) {
console.log(v); // red green blue
}
const obj = {};
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);
//因为obj[Symbol.iterator] 是一个函数,所以要用bind返回的是函数
for(let v of obj) {
console.log(v); // red green blue
}
bind 和 call/apply 一样,都是用来改变上下文 this 指向的,不同的是,call/apply 是直接使用在函数上,而
bind 绑定 this 后返回一个函数
(闭包)
来源于
最后
以上就是潇洒月亮为你收集整理的迭代器.Iterator 和 for...of 循环1.Iterator(遍历器)的概念2默认 Iterator 接口3.for…of 循环的全部内容,希望文章能够帮你解决迭代器.Iterator 和 for...of 循环1.Iterator(遍历器)的概念2默认 Iterator 接口3.for…of 循环所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复