for...of 的秘密:迭代器与可迭代对象,你也能创造“可循环”的东西

发布时间:2026/6/18 14:02:49

for...of 的秘密:迭代器与可迭代对象,你也能创造“可循环”的东西 为什么数组可以用for...of循环为什么对象不行今天我们来揭开JS里“可循环”的秘密——迭代器Iterator和可迭代对象Iterable。弄懂它们你就能让自己的对象也支持for...of甚至还能写出像Python生成器那样优雅的代码。前言你有没有好奇过为什么数组可以用for...of遍历而对象不行为什么...扩展运算符可以展开数组却不能直接展开对象这背后其实是迭代器协议在起作用。今天我们就来彻底搞懂这套机制然后亲手造一个可以for...of遍历的对象。看完你会感叹原来JS的循环还有这么多骚操作一、什么是可迭代对象如果一个对象实现了可迭代协议它就是可迭代对象。可迭代协议要求对象有一个[Symbol.iterator]方法这个方法返回一个迭代器。简单来说可迭代对象 有一个能返回迭代器的方法。数组、字符串、Map、Set、arguments、NodeList等都是原生可迭代对象。所以你可以for(letitemof[1,2,3]){console.log(item);}// 数组for(letcharofhello){console.log(char);}// 字符串for(let[key,val]ofnewMap([[1,2]])){}// Map对象不是可迭代对象所以for...of直接遍历对象会报错。二、迭代器长什么样迭代器是一个对象它有一个next()方法。每次调用next()会返回一个对象{ value: 任意值, done: boolean }。done表示是否遍历结束。比如手动创建一个数组的迭代器constarr[a,b,c];constiteratorarr[Symbol.iterator]();console.log(iterator.next());// { value: a, done: false }console.log(iterator.next());// { value: b, done: false }console.log(iterator.next());// { value: c, done: false }console.log(iterator.next());// { value: undefined, done: true }你看这个迭代器就像个“读取器”每次取一个值直到取完。三、自己实现一个可迭代对象现在我们来造一个可以for...of遍历的对象。比如一个范围对象能遍历从start到end的所有整数。constrange{start:1,end:5,[Symbol.iterator](){letcurrentthis.start;constendthis.end;return{next(){if(currentend){return{value:current,done:false};}else{return{value:undefined,done:true};}}};}};for(letnumofrange){console.log(num);// 1,2,3,4,5}就这么简单只要对象有[Symbol.iterator]方法并且返回一个带有next的对象它就能被for...of遍历。四、扩展运算符、解构赋值背后的迭代器很多JS语法都依赖迭代器...扩展运算符把可迭代对象展开成元素列表数组解构[a, b, ...rest] iterableArray.from()把可迭代对象转成数组for...of循环Promise.all()、Promise.race()的参数也是可迭代对象所以只要你的对象是可迭代的它就能享受这些语法糖。constnumbers[...range];// [1,2,3,4,5]const[first,second,...rest]range;// first1, second2, rest[3,4,5]五、生成器函数迭代器的快捷方式还记得昨天的Generator吗生成器函数返回的就是迭代器所以我们可以用Generator来简化上面的代码constrange{start:1,end:5,*[Symbol.iterator](){for(letithis.start;ithis.end;i){yieldi;}}};是不是简洁多了*[Symbol.iterator]()就是Generator方法每次yield一个值for...of会自动调用next。六、无限迭代器永不停止的循环迭代器可以无限进行下去比如生成斐波那契数列constfibonacci{*[Symbol.iterator](){leta0,b1;while(true){yielda;[a,b][b,ab];}}};constfibfibonacci[Symbol.iterator]();console.log(fib.next().value);// 0console.log(fib.next().value);// 1console.log(fib.next().value);// 1// 想取多少取多少但注意用for...of遍历无限迭代器会死循环所以要手动控制。七、提前终止迭代器return方法如果迭代器被提前终止比如for...of中遇到break或者解构只取前几个值JS会调用迭代器的return方法如果有的话。这可以用来做清理工作。constspecialIterable{[Symbol.iterator](){leti0;return{next(){if(i3)return{value:i,done:false};return{done:true};},return(){console.log(提前终止了);return{done:true};}};}};for(letxofspecialIterable){console.log(x);if(x1)break;// 触发return}// 输出0,1, 然后打印“提前终止了”八、实际应用让对象可迭代假设你有一个用户列表对象你想让它支持for...of直接遍历用户constuserList{users:[{name:张三,age:18},{name:李四,age:20},{name:王五,age:22}],*[Symbol.iterator](){for(letuserofthis.users){yielduser;}}};for(letuserofuserList){console.log(user.name);// 张三 李四 王五}这样你的自定义对象就能像数组一样优雅地遍历了。九、总结迭代器无处不在可迭代对象实现了[Symbol.iterator]方法返回一个迭代器。迭代器实现了next()方法返回{ value, done }。生成器函数是迭代器最便捷的实现方式。很多JS语法for...of、扩展运算符、解构都依赖迭代器协议。理解了这套机制你就能让自定义对象支持for...of创建无限序列深入理解JS语法糖背后的原理下次你写for...of时脑子里可以浮现出迭代器一步步next的画面——这才是真正掌握了JS的底层。明天我们将进入DOM操作与事件流从JS的核心走向与页面的交互。如果你觉得今天的文章够“可迭代”点个赞让更多人看到。我们明天见

相关新闻