迭代器 Iterator

一、迭代器 Iterator

(一)、什么是迭代器

在 JavaScript 中, 迭代器是一种模式,或者是一种特殊的对象,使用迭代器可以以一种统一的方式遍历一个容器对象(如数组、对象、Set、Map等)的元素而无需关心容器的内部实现。

在 ES6 中,JavaScript 引入了正式的迭代器协议和一些内置的迭代器方法如 for...of 循环。

迭代器协议 (Iterator Protocol):定义了一种标准的方式来产生一系列的值
迭代器是一个特殊的对象,每个迭代器对象都拥有一个 next() 方法。当调用这个方法时,它会返回一个包含 valuedone 两个属性的对象:

  • value 属性表示当前迭代的值。
  • done 属性是一个布尔值,表示是否还有更多的值可以迭代,当存在可迭代的值是返回 false,当所有的值都被迭代完成,返回 true 。

可迭代协议(Iterable Protocol):允许对象定义或自定义其迭代行为
对象要实现可迭代协议,则它必须在它或者其原型链上有一个键为 Symbol.iterator 的属性,这个属性对应的值是一个无参数的函数,当调用这个函数时返回一个迭代器。迭代器具有一个 next() 方法,使用这个方法获取下一个要迭代的值。

(二)自定义迭代器、自定义可迭代对象和内置可迭代对象

  • 自定义迭代器
let iterator = {  
  index: 0,  
  array: [1,2,3],  
  next: function() {
    return this.index < this.array.length ? {  
      value: this.array[this.index++],  
      done: false
    } : {
      value: undefined,  
      done: true
    }
  }  
};  
console.log(iterator.next());  // { value: 1, done: false }  
console.log(iterator.next());  // { value: 2, done: false }  
console.log(iterator.next());  // { value: 3, done: false }
console.log(iterator.next());  // { value: undefined, done: true }
  • 自定义可迭代对象
    想要将一个对象变为可迭代对象,则需要在对象上实现Symbol.iterator 方法,这个方法返回一个迭代器对象
    创建自定义可迭代对象分两个步骤:
    • 实现可迭代协议:在自定义对象上定义一个 Symbol.iterator 方法,该方法返回一个迭代器对象
    • 实现迭代器协议:创建一个迭代器对象,该对象具有 next() 方法,该方法在每次调用的时候返回一个包含 valuedone 的对象,value 是当前迭代的值,done 表示是否还有可迭代的值,没有的时候要将 done 设置为 false。设置为 false 则在for … of 中停止取值。
// 可迭代对象
const iteratorObj = {
  // 要迭代的数据
  arr: [1,2,3],
  // 实现 Symbol.iterator 方法以返回迭代器
  [Symbol.iterator]() {
    // 创建一个迭代器对象
    let index = 0
    let self = this
    return {
      next() {
        // 依次获取迭代的元素,done 为 false
        return index < self.arr.length ? {
          value: self.arr[index++],
          done: false
        } : {
          value: undefined,
          done: true // 没有可迭代的元素时,done 设置为 true,结束迭代
        }
      }
    }
  }
}

// 获取迭代器
const iterator = iteratorObj[Symbol.iterator]()
console.log(iterator.next()) // { value: 1, done: false }
console.log(iterator.next()) // { value: 2, done: false }
console.log(iterator.next()) // { value: 3, done: false }
console.log(iterator.next()) // { value: undefined, done: true }
  • 内置可迭代对象
    在 JavaScript 中,许多内置类型 ArrayMapSetStringTypeArrayArgumentsNodeList 都是可迭代的,其原生就具备 iterator 接口,可通过 Symbol.iterator 方法来获取到迭代器。
// 数组
let arr = [1,2,3]
let ArrIterator = arr[Symbol.iterator]()
console.log(ArrIterator.next()) // { value: 1, done: false }
console.log(ArrIterator.next()) // { value: 2, done: false }
console.log(ArrIterator.next()) // { value: 3, done: false }
console.log(ArrIterator.next()) // { value: undefined, done: true }

// Set
let set = new Set([1,2,3])
let setIterator = set[Symbol.iterator]()
console.log(setIterator.next()) // { value: 1, done: false }
console.log(setIterator.next()) // { value: 2, done: false }
console.log(setIterator.next()) // { value: 3, done: false }
console.log(setIterator.next()) // { value: undefined, done: true }

// Map
let map = new Map([['key1',1],['key2',2]])
let mapIterator = map[Symbol.iterator]()
console.log(mapIterator.next()) // {value: ["key1", 1], done: false}
console.log(mapIterator.next()) // {value: ["key2", 2], done: false}
console.log(mapIterator.next()) // {value: undefined, done: true}

// 函数
function fun(a, b) {
  let argumentIterator = arguments[Symbol.iterator]()
  console.log(argumentIterator.next()) // { value: 1, done: false }
  console.log(argumentIterator.next()) // { value: 2, done: false }
  console.log(argumentIterator.next()) // { value: undefined, done: true }
}
fun(1, 2)

(三)、使用 for…of 来遍历可迭代对象

使用 for…of 来遍历可迭代对象,允许遍历可迭代对象的每一个元素,并在每次迭代中,将当前元素的值赋值给一个变量。

  • 数组和Set集合:在 for…of 循环中,数组和Set集合默认使用的迭代器是 values()
// 数组
let arr = [1,2,3]
for(const item of arr) {
  console.log(item)
}
// 1
// 2
// 3

// 获取数据的迭代器,values() 方法返回一个新的 Array Iterator 对象,它按创建时的数组元素的顺序生成一个序列
const arrIterator = arr.values()
console.log(arrIterator.next()) // {value: 1, done: false}

// set
let set = new Set([1,2,3])
for(const item of set) {
  console.log(item)
}
// 1
// 2
// 3
  • Map集合,在 for…of 循环中,默认使用的迭代器是 entries()
let map = new Map()
map.set('name', 'abc')
map.set('age', 18)
for(const [key, value] of map) {
  console.log(`${key}=${value}`)
}
// name=abc
// age=18

const mapIterator = map.entries()
console.log(mapIterator.next()) // {value: ["name", "abc"], done: false}
  • 字符串,也是可迭代对象
let str = 'abc'
for(const item of str) {
  console.log(item)
}

const strIterator = str[Symbol.iterator]()
console.log(strIterator.next()) // {value: "a", done: false}

(四)、可迭代对象的一些使用场景

  • for…of 循环,遍历集合元素
const arr = [1,2,3]
for(const item of arr) {
  console.log(item)
}
  • 解构赋值,从数组或类似数组的对象中获得值时,通过解构赋值允许我们将数组或对象的属性直接赋值给变量。
const [a, ...rest] = [1,2,3]
console.log(a) // 1
console.log(rest) // [2,3]
  • 扩展运算符,扩展运算符(spread)是三个点(…)。它好比 rest 参数的逆运算,允许将一个可迭代对象的元素展开
const arr = [1,2,3]
const arr1 = [...arr, 4, 5]
console.log(arr1) // [1,2,3,4,5]
  • 函数参数,当函数的参数是可迭代对象时,允许将数组或类似数组的对象作为函数的参数
function fun(iterator) {
  for(const item of iterator) {
    console.log(item)
  }
}
fun([1,2,3])
  • 内置方法,Array.from()、Array.prototype.map()、Array.prototype.filter(),接收的参数是一个可迭代对象
const str = 'hello'
const arr = Array.from(str)
console.log(arr) // ['h', 'e', 'l', 'l', 'o']

const numArr = [1,2,3]
const doubArr = numArr.map(num => num*2)
console.log(doubArr) // [2, 4, 6]

const numArr1 = [1,2,3,4,5,6]
const evenArr = numArr1.filter(num => {
  return num % 2 === 0
})
console.log(evenArr) // [2, 4, 6]
  • 异步迭代,通过 for await...of 循环遍历异步可迭代对象
// 创建一个异步生成器函数,返回一个异步迭代器,异步迭代器生产一些异步数据
async function* asyncGenerator() {  
  for (let i = 0; i < 5; i++) {
    // 模拟异步操作,如从API获取数据  
    await new Promise(resolve => setTimeout(resolve, 1000))
    yield i;
  }  
}

(async function() {  
  for await (const value of asyncGenerator()) {  
    console.log(value); // 依次间隔1s输出 0, 1, 2, 3, 4  
  }  
})()

完结,撒花~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值