ES6 之迭代器
作者:Seiya
时间:2019年08月26日
迭代器
JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set。这样就需要一种统一的接口机制,来处理所有不同的数据结构。遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
tips
所谓迭代器,其实就是一个具有 next() 方法的对象,每次调用 next() 都会返回一个结果对象,该结果对象有两个属性,value 表示当前的值,done 表示遍历是否结束。
迭代器的作用
为各种数据结构,提供一个统一的、简便的访问接口;
使得数据结构的成员能够按某种次序排列;
ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费;
可迭代类型
ES6 引入了一个新的 Symbol 对象,symbol 值是唯一的。定义了一个 Symbol.iterator 属性,只要对象中含有这个属性,就是可迭代的,可用于for...of。
原生具备iterator接口的数据(可用for of遍历)
Array
set容器
map容器
String
函数的
arguments
对象NodeList
对象
如下所示:
let str = 'abcd';
let arr = [1, 2, 'kobe', true];
for(let item of str){
console.log(item); // a b c d
}
for(let i of arr){
console.log(i); // 1 2 kobe true
}
function fun() {
for (let i of arguments) {
console.log(i) // 1 4 5
}
}
fun(1, 4, 5)
tips
在ES6中,所有的集合对象,包括数组,Map和Set,还有字符串都是可迭代的,因为他们都有默认的迭代器。
迭代器的工作原理
创建一个指针对象,指向数据结构的起始位置;
第一次调用next方法,指针自动指向数据结构的第一个成员;
接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员;
每调用 next 方法返回的是一个包含 value 和 done 的对象,{ value: 当前成员的值, done: 布尔值 }
value 表示当前成员的值,done 对应的布尔值表示当前的数据的结构是否遍历结束;
当遍历结束的时候返回的 value 值是 undefined,done 值为 true;
内建迭代器
为了更好的访问对象中的内容,比如有的时候我们仅需要数组中的值,但有的时候不仅需要使用值还需要使用索引,ES6 为数组、Map、Set 集合内建了以下三种迭代器:
entries() 返回一个遍历器对象,用来遍历[键名, 键值]组成的数组。对于数组,键名就是索引值。
keys() 返回一个遍历器对象,用来遍历所有的键名。
values() 返回一个遍历器对象,用来遍历所有的键值。
举例如下:
var colors = ["red", "green", "blue"];
for (let index of colors.keys()) {
console.log(index);
}
// 0
// 1
// 2
for (let color of colors.values()) {
console.log(color);
}
// red
// green
// blue
for (let item of colors.entries()) {
console.log(item);
}
// [ 0, "red" ]
// [ 1, "green" ]
// [ 2, "blue" ]
注意:
Set 类型的 keys() 和 values() 返回的是相同的迭代器,这也意味着在 Set 这种数据结构中键名与键值相同。
tips
在 for-of 循环中,如果没有显式指定则使用默认的迭代器。数组和 Set 集合的默认迭代器是 values() 方法,Map 集合的默认迭代器是 entries() 方法。
手写迭代器
遍历器对象除了具有 next 方法,还可以具有 return 方法和 throw 方法。如果你自己写遍历器对象生成函数,那么 next 方法是必须部署的,return 方法和 throw 方法是否部署是可选的。
function createIterator(items) {
var i = 0;
return {
next: function() {
var done = i >= items.length;
var value = !done ? items[i++] : undefined;
return {
done: done,
value: value
};
},
return: function() {
console.log("执行了 return 方法");
return {
value: 404,
done: true
};
}
};
}
tips
return 方法的使用场合是,如果 for...of 循环提前退出(通常是因为出错,或者有 break 语句或 continue 语句),就会调用 return 方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署 return 方法。
注意
for of循环不支持遍历普通对象
对象的Symbol.iterator属性,指向该对象的默认遍历器方法。当使用for of去遍历某一个数据结构的时候,首先去找Symbol.iterator,找到了就去遍历,没有找到的话不能遍历,提示Uncaught TypeError: XXX is not iterable
- 当使用扩展运算符(...)或者对数组和 Set 结构进行解构赋值时,会默认调用 Symbol.iterator 方法