可迭代数据类型
- 原生具有[Symbol.iterator]属性数据类型为可迭代数据类型。如数组、类数组(如arguments、NodeList)、Set和Map。
- 具有迭代器的对象可以使用for…of…进行遍历
let arr = [4, 2, 1];
// 这就是迭代器
let iterator = arr[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// {value: 4, done: false}
// {value: 2, done: false}
// {value: 1, done: false}
// {value: undefined, done: true}
//Set中的迭代器
let list = new Set([1,3,2,3])
let it = list.entries() // 获取set集合中自带的的迭代器
console.log(it.next()) // { value: [ 1, 1 ], done: false }
console.log(it.next()) // { value: [ 3, 3 ], done: false }
console.log(it.next()) // { value: [ 2, 2 ], done: false }
console.log(it.next()) // { value: undefined, done: true }
自定义迭代器
- 若要为对象实现for…of…遍历,需要手动实现Symbol.iterator方法
let obj = {
name : 'tom',
age : 18,
gender : '男',
intro : function(){
console.log('my name is '+this.name)
},
[Symbol.iterator]:function(){
let i = 0;
// 获取当前对象的所有属性并形成一个数组
let keys = Object.keys(this);
return {
next: function(){
return {
// 外部每次执行next都能得到数组中的第i个元素
value:keys[i++],
// 如果数组的数据已经遍历完则返回true
done:i > keys.length
}
}
}
}
}
for(let attr of obj){
console.log(attr);
}
Generator中的生成器
- 生成器本身就是一个迭代器。
- 生成器也可以调用next,返回的也是value和done这样的数据结构
function* A() {
console.log("我是A");
yield B(); // A停住,在这里转交线程执行权给B
console.log("结束了");
}
function B() {
console.log("我是B");
return 100;// 返回,并且将线程执行权还给A
}
let gen = A();
gen.next();
gen.next();
// 我是A
// 我是B
// 结束了
- 生成器也属于迭代器,固生成器也可以使用迭代器进行遍历
function *foo() {
yield 1
yield 2
yield 3
yield 4
yield 5
return 6
}
for (let v of foo()) {
console.log(v)
}
// 1 2 3 4 5
和forEach、普通for循环的区别
//forEach
// 核心逻辑
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
callback(element, i, array);
}
}
//for...of...是下面这样的语法糖
async function test() {
let arr = [4, 2, 1]
let iterator = arr[Symbol.iterator]();
let res = iterator.next();
while(!res.done) {
let value = res.value;
console.log(value);
res = iterater.next();
}
console.log('结束')
}
// 4
// 2
// 1
// 结束
迭代器作用场景
- 解决循环await异步阻塞失效
async function test() {
let arr = [4, 2, 1]
//await并不能阻塞,最终输出1、2、4
//原因是forEach是直接拿到回调执行,并不能保证异步的顺序
arr.forEach(async item => {
const res = await handle(item)
console.log(res)
})
console.log('结束')
}
function handle(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x)
}, 1000 * x)
})
}
test()
//解决方式
async function test() {
let arr = [4, 2, 1]
for(const item of arr) {
const res = await handle(item)
console.log(res)
}
console.log('结束')
}