可迭代对象
可迭代对象你可以理解为内部可循环遍历的对象。
在ES6中,可迭代有Array、Map、Set 还有 String;
当然还有一些特殊类型比如生成器(Generator)。
迭代方式
我就不带大家手写迭代器了,直接教大家应用。
下面以Generator为例向大家介绍两种迭代方式,第二种大家最熟悉。
1.Generator.next()
第一种是Generator 自带的迭代方式。
为什么我要从这个比较晦涩难懂的开始讲而不是先将for in , for of 呢?因为后面会让你们重新认识第一种。
首先我们创建一个Generator 函数。
function* func(){
yield 1;
yield 2;
yield 3;
}
此时 func 是一个 生成器函数 [Generator Function] , 这里的 * 号虽然放在哪都没关系,这里的 * 与后面的 * 意义不同,这里声明的 [Generator Function] 不是一个可迭代对象,为了区分,我强烈建议大家放在funtion后,而不是函数名前。
我们执行该函数,会获得一个 Generator 对象,该对象是一个可迭代对象。
这里一定要区分 [Generator Function] 和 [Generator] ,否则你后面会更加混淆!!!
究竟什么是可迭代对象????大家别着急,我会慢慢向你解释什么是可迭代对象。
我们先用Generator自带的.next()迭代该对象。
let _func = func(); //此时 _func 是一个可迭代对象[Generator]
_func.next(); //{value:1, done:false}
_func.next(); //{value:2, done:false}
_func.next().value; //3
看不懂?没关系,我说过,迭代器有两种迭代方式,而Generator也是迭代器的一种。不过我还是强烈建议您补一下Generator的基础再来看我的文章,这篇文章的重点不是教你怎么用 Generator的。
上面的方法是一种迭代方式。
2.for in 、 for of
for in和 for of 是基于迭代器实现的;废话不多说,直接改写上面的例子
function* func(){ //func 是[Generator Function],不可迭代,别混淆!
yield 1;
yield 2;
yield 3;
}
let _func = func(); // _func 是一个可迭代对象 [Generator]
for(let i of _func){
console.log(i);
}
// 1
// 2
// 3
Generator对象可以使用 for of 遍历,并且结果等价 Generator.next().value
我们尝试一下 for in :
for(let i in _func){
console.log(i);
}
//undefined
这里不用惊讶,因为能使用for in的往往都是具有内部索引的可迭代对象,比如 String 和 Array,我们尝试一下无内部索引的Set 对象。
let arr = [1,2,3];
let set = new Set(arr);
for(let i in arr){
console.log(i)
}
// 0
// 1
// 2
for(let i in set){
console.log(i)
}
//undefined
以上例子也说明Generator没有内部索引,因此大多数情况下我们使用 for of 能更方便遍历所有可迭代对象。
通过 yield * 迭代 可迭代对象
yield * 可以将一个可迭代对象进行迭代返回,这么说有点抽象,直接上例子。
function* func1(nums) {
yield nums;
}
for (let item of func1([1, 2, 3])) { //这里 func1([1,2,3]) 获取的就是一个 Generator对象,这是简写希望你能看懂
console.log(item)
}
// [1, 2, 3]
可以看见,不使用yield * 来迭代 nums,那么获取到的就是整个nums数组对象。
如果我们使用了 yield *
function* func1(nums) {
yield *nums;
}
for (let item of func1([1, 2, 3])) {
console.log(item)
}
// 1
// 2
// 3
这样,nums就会作为一个可迭代对象被迭代,然后返回其所有内部值。
下一个例子,我将引入其他可迭代对象。
let arr=[1,2,3];
let set = new Set(arr); // Set
let str = "abcd"; // string
let map = new Map([["name","dz"],["age","21"],["hobby","music"]]);
let obj = {name:"dz",age:"21",hobby:"music"}; //Object类型是不可迭代对象。 Uncaught TypeError: obj is not iterable
function* func1(nums) {
yield *set;
yield *str;
yield *map;
yield *obj
}
for (let item of func1()) {
console.log(item)
}
// 1
// 2
// 3
// a
// b
// c
// d
// ["name", "dz"]
// ["age", "21"]
// ["hobby", "music"]
// Uncaught TypeError: xxx..
可以看见,只要能迭代的类型,yield * 都能正常迭代返回。
可以通过for of 来判断一个类型是否能够迭代,比如对象类型就不能使用for of迭代。
当然别忘了,Generator 本身也是一个可迭代对象!!!
我将举一个特别典型的例子来帮你更加理解可迭代对象。
这个例子如果懂了,我觉得你几乎吃透了这个知识点,不说了开始套娃。
function* func1(...nums) {
yield "--func1--";
yield* nums;
yield* func2(101, 102); //func2() 返回的Generator 也可以迭代
yield "--end--";
}
function* func2(...nums) {
yield "--fun2--";
yield nums;
yield* nums;
yield*"对不起";
yield* func3("邓洲", "呀")
}
function* func3() {
yield "--func3--";
yield* arguments; //arguments也是可迭代对象
yield* funcNoStar(arguments); //函数返回值是可迭代对象也可以
}
function funcNoStar(arr) {
let res = ["--funcNoStar--"];
for (let a of arr) {
res.push(...a)
}
return res;
}
for (let item of func1(1, 2, 3)) {
console.log(item)
}
最后结果