js 迭代器

本文介绍了JavaScript中的可迭代数据类型,如数组、Set和Map,以及如何通过Symbol.iterator实现自定义迭代器。此外,还详细阐述了生成器的概念,展示了如何使用生成器进行迭代,并解释了它们在异步编程中的作用,特别是在解决forEach循环中await异步阻塞问题的应用。最后,对比了forEach、普通for循环与for...of...的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可迭代数据类型

  • 原生具有[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('结束')
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值