tk挠痒痒网址发布页-秘密武器
历史搜索

深究JavaScript 中的迭代器

游客2025-05-15 01:16:28
目录文章目录
  1. Iterator 迭代器
  2. 可迭代对象
  3. 提前退出循环
  4. Iterator 接口使用场景
  5. 总结

深究JavaScript 中的迭代器 1

其余几种都一个套路,不多说

Q&A

看到这里你可能会想,为什么这么多数据结构都实现了默认部署,为什么偏偏对象没有呢?

当然是有原因的

对象可能有各种各样的属性,不像数组的值是有序的,所以对对象遍历时根本不知道如何确定先后顺序,所以需要我们手动实现。

提前退出循环

普通的 for 循环是可以随时中断的,for...of 循环作为 for 和 forEach 的升级版同样是可以的。

迭代器对象除了有 next 方法,还有两个可选方法 return 方法和 throw 方法。

return 方法的使用场景是,当 for...of 循环提前退出,就会调用 return 方法。

需要特别注意的是,return 方法必须有一个 object 类型的返回值。

我们在前面代码的基础上添加上 return 方法,并在 for...of 循环中采用 break 语句来中断循环,循环提前退出,自动调用 return 方法输出提前退出。

let iteratorObj = {
    items: [1, 2, 'mybj'],
    // 部署 Symbol.iterator 属性
    [Symbol.iterator]: function () {
        let self = this
        let i = 0
        return {
            next: function () {
                // 类型转化为 Boolean
                let done = (i >= self.items.length)
                // 数据确认
                let value = !done ? self.items[i++] : undefined
                // 数据返回
                return {
                    done,
                    value
                }
            },
            return () {
                console.log('提前退出');
                return {
                    done: true
                }
            }
        }
    }
}
for (let item of iteratorObj) {
    console.log(item); // 1
    break;
}

注意:

如果采用抛出异常的方式退出,会先执行 return 方法再抛出异常。

关于 throw 方法会在下篇生成器文章中提到。

Iterator 接口使用场景

除了 for...of 循环会自动调用 iterator 接口之外,还有几个场景也会自动调用

1. 解构赋值

对可迭代对象进行解构赋值时,会默认调用 Symbol.iterator 方法

let map = new Set().add('a').add('b');
let [x, y] = map
console.log(x, y, map) // a b Set(2) {"a", "b"}

由于解构赋值适用于可迭代对象,那么我们对自己自定义的可迭代对象解构赋值试试。

let iteratorObj = {
    items: [1, 2, 'mybj'],
    // 部署 Symbol.iterator 属性
    [Symbol.iterator]: function () {
        let self = this
        let i = 0
        return {
            next: function () {
                // 类型转化为 Boolean
                let done = (i >= self.items.length)
                // 数据确认
                let value = !done ? self.items[i++] : undefined
                // 数据返回
                return {
                    done,
                    value
                }
            }
        }
    }
}
let [a, b, c] = iteratorObj
console.log(a, b, c)// 1 2 'mybj'

成功的实现了解构赋值

2. 扩展运算符

扩展运算符也会默认调用Symbol.iterator方法,可以将当前数据结构转化为数组

// 阮老师的例子
var str = 'hello';
[...str] //  ['h','e','l','l','o']
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']

3. yield*

yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。

let generator = function* () {
  yield 1;
  yield* [2,3,4];
  yield 5;
}

这里并不是它的主战场,下节说明~

总结

在 ES6 中新增了新的数据结构,为了提供一种统一的遍历方法,新增了 for...of 方式。而 for...of 执行的时候会自动调用迭代器来取值

只有实现了 Iterator 接口的对象才能采用 for...of

迭代器是一个返回迭代器对象的方法

ES6 中很多场景都采用了 Iterator ,可以多注意一下,新的东西往往是向上的。

下一篇将来讲解生成器Generator,持续关注哦!

本文是由用户"游客"发布,所有内容的版权归原作者所有。没有经过书面许可,任何单位或个人不得以任何形式复制、转载、引用本网站的内容。否则将追究法律责任。

相关专题