ECMAScript6(14):iterator 迭代器

本文详细对比了JavaScript中for…of与for…in的使用,强调了for…of遍历值的优势,包括数组、Set、Map、字符串和类数组对象的实例,并介绍了自定义遍历器和技巧。通过实例展示了如何利用这些特性高效地遍历数据结构。

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

不难看出 for…of 默认得到值, 而 for…in 只能得到索引。当然数组的 for…of 只返回数字索引的属性, 而 for…in 没有限制:

var arr = [“red”, “green”, “blue”];

arr.name = “color”;

for(let v of arr){

console.log(v); //依次输出 “red”, “green”, “blue”

}

for(let i in arr){

console.log(arr[i]); //依次输出 “red”, “green”, “blue”, “color”

}

  • Set

默认 for…of 遍历器遍历值

var set = new Set([“red”, “green”, “blue”]);

for(let v of set){ //相当于 for(let i in arr.values())

console.log(v); //依次输出 “red”, “green”, “blue”

}

for(let [key, value] of set.entries()){

console.log(key + ": " + value); //依次输出 “red: red”, “green: green”, “blue: blue”

}

for(let key of set.keys()){

console.log(key); //依次输出 “red”, “green”, “blue”

}

  • map

默认 for…of 遍历器遍历键值对

var map = new Map();

map.set(“red”, “#ff0000”);

map.set(“green”, “#00ff00”);

map.set(“blue”, “#0000ff”);

for(let [key, value] of map){ //相当于 for(let i in arr.entries())

console.log(key + ": " + value); //依次输出 “red: #ff0000”, “green: #00ff00”, “blue: #0000ff”

}

for(let value of map.values()){

console.log(value); //次输出 “#ff0000”, “#00ff00”, “#0000ff”

}

for(let key of map.keys()){

console.log(key); //次输出 “red”, “green”, “blue”

}

  • 字符串

for…of可以很好的处理区分32位 Unicode 字符串

var str = “Hello”;

for(let v of str){

console.log(v); //依次输出 “H”, “e”, “l”, “l”, “o”

}

  • 类数组对象

// DOM NodeList

var lis = document.getElementById(“li”);

for(let li of lis){

console.log(li.innerHTML); //遍历每个节点

}

//arguments

function fun(){

for(let arg of arguments){

console.log(arg); //遍历每个参数

}

}

不是所有类数组对象都有 iterator, 如果没有, 可以先用Array.from()进行转换:

var o = {0: “red”, 1: “green”, 2: “blue”, length: 3};

var o_arr = Array.from(o);

for(let v of o_arr){

console.log(v); //依次输出 “red”, “green”, “blue”

}

技巧1: 添加以下代码, 使 fo 《大厂前端面试题解析+Web核心总结学习笔记+企业项目实战源码+最新高清讲解视频》无偿开源 徽信搜索公众号【编程进阶路】 r…of 可以遍历 jquery 对象:

$.fn[Symbol.iterator] = [][Symbol.iterator];

技巧2: 利用 Generator 重新包装对象:

function* entries(obj){

for(let key of Object.keys(obj)){

yield [key, obj[key]];

}

}

var obj = {

red: “#ff0000”,

green: “#00ff00”,

blue: “#0000ff”

};

for(let [key, value] of entries(obj)){

console.log(${key}: ${value}); //依次输出 “red: #ff0000”, “green: #00ff00”, “blue: #0000ff”

}

几种遍历方法的比较

  • for 循环: 书写比较麻烦

  • forEach方法: 无法终止遍历

  • for…in: 仅遍历索引, 使用不便捷; 会遍历原型链上的属性, 不安全; 会遍历非数字索引的数组属性;

  • for…of:

iterator 与 [Symbol.iterator]

iterator 遍历过程是这样的:

1. 创建一个指针对象, 指向当前数据结构的起始位置。即遍历器的本质就是一个指针。

2. 调用一次指针的 next 方法, 指针指向第一数据成员。之后每次调用 next 方法都会将之后向后移动一个数据。

3. 知道遍历结束。

我们实现一个数组的遍历器试试:

var arr = [1, 3, 6, 5, 2];

var it = makeIterator(arr);

console.log(it.next()); //Object {value: 1, done: false}

console.log(it.next()); //Object {value: 3, done: false}

console.log(it.next()); //Object {value: 6, done: false}

console.log(it.next()); //Object {value: 5, done: false}

console.log(it.next()); //Object {value: 2, done: false}

console.log(it.next()); //Object {value: undefined, done: true}

function makeIterator(arr){

var nextIndex = 0;

return {

next: function(){

return nextIndex < arr.length ?

{value: arr[nextIndex++], done: false} :

{value: undefined, done: true}

}

};

}

由这个例子我们可以看出以下几点:

  • 迭代器具有 next() 方法, 用来获取下一元素

  • next() 方法具有返回值, 返回一个对象, 对象 value 属性代表下一个值, done 属性表示是否遍历是否结束

  • 如果一个数据结构本身不具备遍历器, 或者自带的遍历器不符合使用要求, 请按此例格式自定义一个遍历器。

其实一个 id 生成器就很类似一个遍历器:

function idGen(){

var id = 0;

return {

next: function(){ return id++; }

};

}

var id = idGen();

console.log(id.next()); //0

console.log(id.next()); //1

console.log(id.next()); //2

//…

对于大多数数据结构, 我们不需要再像这样写遍历器函数了。因为他们已经有遍历器函数[Symbol.iterator], 比如Array.prototype[Symbol.iterator] 是数组结构的默认遍历器。

下面定义一个不完整(仅包含add()方法)的链表结构的实例:

function Node(value){

this.value = value;

this.next = null;

}

function LinkedList(LLName){

this.head = new Node(LLName);

this.tail = this.head;

}

var proto = {

add: function(value){

var newNode = new Node(value);

this.tail = this.tail.next = newNode;

return this;

}

}

LinkedList.prototype = proto;

LinkedList.prototype.constructor = LinkedList;

LinkedList.prototype[Symbol.iterator] = function(){

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值