ES6 自定义迭代器如何做到像原生迭代器那样实现 Iterable 接口?

发布于 2022-09-12 22:12:53 字数 1133 浏览 19 评论 0

ES6 中原生实现了迭代器的数据结构可以像下面那样使用for of进行遍历

const arr = [ 1, 2, 3 ]
const iter = arr[Symbol.iterator]()
for (const item of iter) {
    console.log(item) // 1 2 3
}
const iter2 = iter[Symbol.iterator]()
console.log(iter === iter2) // true
const iter3 = iter[Symbol.iterator]()[Symbol.iterator]()[Symbol.iterator]()
console.log(iter === iter3) // true

问题是我自定义了一个迭代器,如何像原生迭代器那样实现Iterable接口来做到像上面那样使用 for of?

class Counter {
  constructor(limit) {
    this.limit = limit
  }
  [Symbol.iterator]() {
    let count = 1,
        limit = this.limit
    return {
      next() {
        if (count <= limit) {
          return { done: false, value: count++ }
        } else {
          return { done: true, value: undefined }
        }
      },
      [Symbol.iterator]() {
        // 这里该如何实现?
      }
    }
  }
}

const counter = new Counter(5)
const iter = counter[Symbol.iterator]()
const iter2 = iter[Symbol.iterator]()
console.log(iter === iter2) // false

for (const item of iter) { // Undefined is not a function
    // Some Code
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

提赋 2022-09-19 22:12:53
class Counter {
    constructor(limit) {
        this.limit = limit;

        // 把迭代器返回结果的迭代器指向迭代器[滑稽]
        this._iteratorResult[Symbol.iterator] = this[Symbol.iterator]
    }

    _iteratorResult = {
        next:() => {
            let count = 1,
                limit = this.limit
            if (count <= limit) {
                return { done: false, value: count++ }
            } else {
                return { done: true, value: undefined }
            }
        }
    };

    // 使用箭头函数,确保迭代器的 this 指向实例
    // 当然也可以在构造函数里赋值的时候用 bind 函数绑定
    [Symbol.iterator] = () => {
        return this._iteratorResult
    }
}
懒猫 2022-09-19 22:12:53

用生成器,而且对象有迭代器的话for...of会自动执行的,不需要显式的去执行

class Counter {
  constructor(limit) {
    this.limit = limit
  }
  *[Symbol.iterator]() {
    let count = 1,
        limit = this.limit;
    while(count<=limit) {
        yield count++
    }
  }
}
var counter = new Counter(5)
for (var v of counter) { // Undefined is not a function
    // Some Code
    console.log(v)
}
椒妓 2022-09-19 22:12:53

之前还没意识到这个问题,这说明内置可迭代对象返回的迭代器也是个可迭代对象(额,有点绕~)并且两者的迭代器是相等的,回到你自定义的Counter,这样修改:

class Counter {
  constructor(limit) {
    this.limit = limit
  }
  [Symbol.iterator]() {
    let count = 1,
        limit = this.limit,
        iterator = {
          next() {
            if (count <= limit) {
              return { done: false, value: count++ }
            } else {
              return { done: true, value: undefined }
            }
          },
          [Symbol.iterator]() {
            return iterator;
          }
        };
        
    return iterator;
  }
}

const counter = new Counter(5)
const iter = counter[Symbol.iterator]()
const iter2 = iter[Symbol.iterator]()
console.log(iter === iter2) // true
const iter3 = iter[Symbol.iterator]()[Symbol.iterator]()[Symbol.iterator]()
console.log(iter === iter3) // true
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文