0


JS - iterator(迭代器)

一、 概念

   JavaScript原有表示“集合”的数据结构,主要是数组(' Array ')和对象(' Object ' ),ES6又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理不同的数据结构。
    遍历器(Iterator)就是这样一种机制。它是一种接口,为不同的数据结构提供一种访问机制,即for ... of 循环。当使用
for...of

循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。

二、本质

    **迭代器对象本质上,就是一个指针对象。通过指针对象的next(), 用来移动指针。
     ****迭代器协议:对象必须提供一个next(),执行该方法要么返回迭代的下一项,要么就引起Stopiteration异常,以终止迭代。**
     每调用一次next ()方法,都会返回一个对象,都会返回数据结构的当前成员的信息。这个对象有 value 和 done 两个属性,value属性返回当前位置的成员,done属性是一个布尔值,表示遍历是否结束,即是否有必要再调用一次next () 。对于遍历器来说,value:undefined和done:false属性都是可以省略的。
     ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性上;或者说,一个数据结构只要有Symbol.iterator属性,就认为是可遍历的。

三、实现Iterator接口的原生对象

原生具备Iterator接口的数据结构有:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

可以看到Array原型对象已经实现了Iterator这个属性:

那么数组的实例对象也拥有这个属性,可以调用试试:

下面是模拟next()方法返回的例子:

   上面的代码定义了一个makeIterator函数,它是一个遍历器生成的函数,作用就是返回一个遍历器对象。**对数组[ ’a', 'b' ]执行这个函数,就会返回该数组的遍历器对象(指针对象)it**。指针对象的
next

方法,用来移动指针。开始时,指针指向数组的开始位置。然后,每次调用

next

方法,指针就会指向数组的下一个成员。第一次调用,指向

a

;第二次调用,指向

b


** 总之,调用指针对象的next()方法,就可以遍历事先给定的数据结构。**
上面说了,对于遍历器对象来说, done:false 和 value:undefined属性都是可以省略的,因此上面的

makeIterator

函数可以简写成下面的形式。

** 使用场合:**

① 对实现了Iterator接口的数据解构赋值

② 扩展运算符

上面代码的扩展运算符内部就调用 Iterator 接口。

实际上,这提供了一种简便机制,可以将任何部署了 Iterator 接口的数据结构,转为数组。也就是说,只要某个数据结构部署了 Iterator 接口,就可以对它使用扩展运算符,将其转为数组。

三、 for... of 循环

for...of

循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如

arguments

对象、DOM NodeList 对象)、字符串等。

数组原生具备iterator接口,(默认部署Symbol.iterator属性),for...of 循环本质上就是调用这个接口产生的遍历器:

const arr = ['red', 'green', 'blue'];

for(let v of arr) {
  console.log(v); // red green blue
}

const obj = {};
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);

for(let v of obj) {
  console.log(v); // red green blue
}

上面代码中,空对象

obj

部署了数组

arr

Symbol.iterator

属性,结果

obj

for...of

循环,产生了与

arr

完全一样的结果。

for ... of 循环可以代替数组实例 forEach 方法。

const arr = ['red', 'green', 'blue'];

arr.forEach(function (element, index) {
  console.log(element); // red green blue
  console.log(index);   // 0 1 2
});

JavaScript 原有的

for...in

循环,只能获得对象的键名,不能直接获取键值。ES6 提供

for...of

循环,允许遍历获得键值。

var arr = ['a', 'b', 'c', 'd'];

for (let a in arr) {
  console.log(a); // 0 1 2 3
}

for (let a of arr) {
  console.log(a); // a b c d
}

四、 Set 和 Map结构

Set和Map结构也原生具有Interator接口,可以直接使用for...of循环。

var engines = new Set(['1','2','3']);
for (var e of engines) {
  console.log(e);   // 1  2  3
} 

var class = new Map();
class .set('Tom', 12);
class .set('Lala', 13);
class .set('9300', 14);
for (var [name,value] of class) {
  console.log(name + ':' + number);    // Tom:12  Lala:13  9300:14
}     

以上代码演示了如何遍历Set和Map结构。需要注意的是,首先遍历的顺序是按照哥哥成员被添加进数据结构的顺序。其次,Set结构遍历时,返回的是一个值。而Map结构遍历时,返回的是一个数组,该数组的两个成员分别是当前Map成员的键名和键值。

let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
  console.log(pair);
}
// ['a', 1]
// ['b', 2]

for (let [key, value] of map) {
  console.log(key + ' : ' + value);
}
// a : 1
// b : 2

其他内容可参照 ES6入门

标签: javascript 前端 html

本文转载自: https://blog.csdn.net/m0_52545254/article/details/126741625
版权归原作者 93 Million Miles- 所有, 如有侵权,请联系我们删除。

“JS - iterator(迭代器)”的评论:

还没有评论