欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JS Iterator 迭代协议

程序员文章站 2024-02-20 20:24:34
...

一个对象, 默认是不可迭代的

let foo = {
  foo1: 1,
  foo2: 2
}

// 如果使用 of 或 展开运算符迭代 foo   会报错
for (const v of foo) {
  console.log(v)
}
console.log([...foo])

那么, 如何使得 foo 变的可迭代呢?

最基本的不会报错的写法, 给 foo 这个对象添加一个 [Symbol.iterator] 的键, 其值为一个函数, 函数取啥名不重要, 重要的是它会返回一个具有 next 函数的对象

let foo = {
  foo1: 1,
  foo2: 2,
  [Symbol.iterator]: () => {
    return {
      next() {
        return { done: true }
        // return { done: false, value: 'xxx' }
      }
    }
  }
}
console.log([...foo])

这样就不会报错了, 但是打印出来的结果只是一个空数组

如果想打印 foo 的键值呢?

let foo = {
  foo1: 1,
  foo2: 2,
  [Symbol.iterator]: function abandomName() {
    let fooKey = Object.keys(foo)
    return {
      next() {
        if (fooKey.length) {
          return { done: false, value: fooKey.pop() }
        }
        return { done: true }
      }
    }
  }
}
console.log([...foo])

你还可以将 [Symbol.iterator] 对应的函数抽出来

let fooKey = ['foo1', 'foo2']

let iterator = {
  next() {
    if (fooKey.length) {
      return { done: false, value: fooKey.pop() }
    }
    return { done: true }
  }
}

let foo = {
  [Symbol.iterator]() {
    return iterator
  }
}
console.log([...foo])

可以看到, next 用于定制迭代的行为, 如果我想打印 1 ~ 9

let a = 0
const iterator = {
  next() {
    a++
    if (a > 9) {
      return { done: true }
    }
    return { done: false, value: a }
  }
}

const oneToNine = {
  [Symbol.iterator]: () => {
    return iterator
  }
}
console.log([...oneToNine])

我将 iterator 单独抽出来的写法

let a = 0
const iterator = {
  next() {
    a++
    if (a > 9) {
      return { done: true }
    }
    return { done: false, value: a }
  }
}

let iteratorRes = iterator.next()
while(!iteratorRes.done) {
  console.log(iteratorRes.value)
  iteratorRes = iterator.next()
}

迭代协议

for…of