Iterator
遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。
在ES6中,有些数据结构原生具备Iterator接口(比如数组),即不用任何处理,就可以被for...of循环遍历,有些就不行(比如对象)。原因在于,这些数据结构原生部署了Symbol.iterator属性(详见下文),另外一些数据结构没有。凡是部署了Symbol.iterator属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。
在ES6中,有三类数据结构原生具备Iterator接口:数组、某些类似数组的对象、Set和Map结构。
一个为对象添加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
};
} else {
return { value: undefined, done: true };
}
}
};
}
};
有一些场合会默认调用Iterator接口:
-
解构赋值
-
扩展运算符(...)
-
yield* 后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
-
由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用
字符串是一个类似数组的对象,也原生具有Iterator接口。
遍历器对象除了具有next方法,还可以具有return方法和throw方法。如果你自己写遍历器对象生成函数,那么next方法是必须部署的,return方法和throw方法是否部署是可选的.
for...of 、forEach 和 for...in 的区别
forEach
对数组的每一个元素执行一次提供的函数(不能使用return、break等中断循环),不改变原数组,无返回值undefined。
let arr = ['a', 'b', 'c', 'd']
arr.forEach(function (val, idx, arr) {
console.log(val + ', index = ' + idx) // val是当前元素,index当前元素索引,arr数组
console.log(arr)
})
输出:
a, index = 0
(4) ["a", "b", "c", "d"]
b, index = 1
(4) ["a", "b", "c", "d"]
c, index = 2
(4) ["a", "b", "c", "d"]
d, index = 3
(4) ["a", "b", "c", "d"]
for…of
它是ES6中新增加的语法,用来循环获取一对键值对中的值。
一个数据结构只有部署了 Symbol.iterator 属性, 才具有 iterator接口可以使用 for of循环
所以可以用来循环遍历数组,而不能循环遍历对象
let arr = ['China', 'America', 'Korea']
for (let o of arr) {
console.log(o) //China, America, Korea
}
// error
let obj = {a: '1', b: '2', c: '3', d: '4'}
for (let o of obj) {
console.log(o) //Uncaught TypeError: obj[Symbol.iterator] is not a function
}
for…in
循环遍历的值都是数据结构的键值
let obj = {a: '1', b: '2', c: '3', d: '4'}
for (let o in obj) {
console.log(o) //遍历的实际上是对象的属性名称 a,b,c,d
console.log(obj[o]) //这个才是属性对应的值1,2,3,4
}
posted on
浙公网安备 33010602011771号