TypeScript | 迭代器 Iterator

迭代器是一种特殊对象,它符合迭代器协议规范。在 TypeScript 中,我们可以定义一个接口,这个接口上有一个函数类型 nextnext() 方法的返回值类型是 { value: any, done: boolean }。其中,value 是 any 类型,表示下一个将要返回的值;done 是布尔类型,当没有更多可返回数据时返回 true。迭代器还会保存一个内部指针,用来指向当前集合中值的位置。

迭代器一旦创建,迭代器对象就可以通过重复调用 next() 显式地迭代。

模拟一个简略的迭代器

// 声明了一个 Iterator 接口,具有 next 这样一个函数类型
interface IteratorInterface {
  next: () => {
    value: any
    done: boolean
  }
}

// 声明了一个可以返回迭代器对象的函数,这个函数的返回值类型必须符合 Iterator 接口
function createIterator(array: any[]): IteratorInterface {
  let index = 0
  let len = array.length

  return {
    next: function () {
      return index < len ? { value: array[index++], done: false } : { value: undefined, done: true }
    }
  }
}

var iterator = createIterator([1, 2, 3])

console.log(iterator.next()) // { value: 1, done: false }
//通过调用迭代器对象上的 next() 方法,可以拿到数据集中的下一个数据项

console.log(iterator.next()) // { value: 2, done: false }
console.log(iterator.next()) // { value: 3, done: false }
console.log(iterator.next()) // { value: undefined, done: true }
//拿到数据集中的所有数据后,done 属性变为 true
复制代码

可迭代性

当一个对象实现了Symbol.iterator属性时,我们认为它是可迭代的。 一些内置的类型如 Array,Map,Set,String,Int32Array,Uint32Array等都已经实现了各自的Symbol.iterator。 对象上的 Symbol.iterator 函数负责返回供迭代的值。

String 是一个内置的可迭代对象:

let str: string = 'Hi'
console.log(typeof str[Symbol.iterator]) // function
复制代码

String 的默认迭代器会依次返回该字符串的字符:

// 字符串类型变量,内置了默认迭代器生成函数 Symbol.iterator
let str: string = 'Hi'
// 执行这个函数,返回了一个迭代器
let iterator: IterableIterator<string> = str[Symbol.iterator]() 
 
console.log(iterator.next())      // { value: 'H', done: false }
console.log(iterator.next())      // { value: 'i', done: false }
console.log(iterator.next())      // { value: undefined, done: true }
复制代码

迭代器的作用:

  • 为各种数据结构(Array,Map,Set,String等),提供一个统一的、简便的访问接口。
  • 使得数据结构的成员能够按某种次序排列。
  • 创造了一种新的遍历命令 for..of 循环。

for…of

for...of 会遍历可迭代的对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等),调用对象上的 Symbol.iterator 方法。

迭代数组

示例:

let iterable = [10, 20, 30]
// 通过 for...of 循环遍历数组 iterable 的每一项元素
for (const value of iterable) {
  console.log(value)
}
// 依次输出 10 20 30
复制代码

示例:

const heroes = [
  {
    name: '艾希',
    gender: 2
  },
  {
    name: '泰达米尔',
    gender: 1
  }
]

for (let { name } of heroes) {
  console.log(name)
}
复制代码

通过 let { name } of heroes 循环迭代 heroes 对象数组,将每一个对象解构,得到每一个对象的 name 属性值

迭代字符串

字符串具有可迭代性,通过 for…of 可以快速遍历出每一个字符:

let iterable = 'abc'

for (const s of iterable) {
  console.log(s)
}
// 依次输出 a b c
复制代码

迭代 Map

let iterable = new Map()

iterable.set('a', 1)
iterable.set('b', 2)
iterable.set('c', 3)

for (let entry of iterable) {
  console.log(entry)
}
// ['a', 1]
// ['b', 2]
// ['c', 3]

for (let [key, value] of iterable) {
  console.log(value)
}
// 1
// 2
// 3
复制代码

解释: 一个 Map 对象在迭代时会根据对象中元素的插入顺序来进行。for...of 循环在每次迭代后会返回一个形式为 [key,value] 的数组。通过使用 let [key, value] 这种解构形式,可以快速获取每一项属性值。

for…of 与 for…in 的区别

for..of和for..in均可迭代一个列表;但是用于迭代的值却不同,for..in迭代的是对象的 键 的列表,而for..of则迭代对象的键对应的值。

let list = [4, 5, 6];

for (let i in list) {
    console.log(i); // "0", "1", "2",
}

for (let i of list) {
    console.log(i); // "4", "5", "6"
}
复制代码

for...in 可以操作任何对象,它提供了查看对象属性的一种方法。 但是 for...of 关注于可迭代对象的值。内置对象Map和Set已经实现了Symbol.iterator方法,让我们可以访问它们保存的值。

let pets = new Set(["Cat", "Dog", "Hamster"]);
pets["species"] = "mammals";
//pets-- Set(3) { 'Cat', 'Dog', 'Hamster', species: 'mammals' }
for (let pet in pets) {
    console.log(pet); // "species"
}

for (let pet of pets) {
    console.log(pet); // "Cat", "Dog", "Hamster"
}
复制代码

解构赋值与扩展运算符

对数组和 Set 结构进行解构赋值时,会默认调用 Symbol.iterator 方法:

let [head, ...tail] = [1, 2, 3, 4]
// tail = [2, 3, 4]
复制代码

扩展运算符也会调用默认的 Iterator 接口,得到一个数组结构:

let arr = [...'hello']
console.log(arr) //  ['h','e','l','l','o']
复制代码

学习链接

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享