发表于: 2019-11-20 09:09:11

0 1282


js基础 - 续2

Iterables(可迭代对象 http://es6.ruanyifeng.com/#docs/iterator

迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。

Iterable (可迭代对象)是数组的泛化。这个概念是说任何对象都可在 for..of 循环中使用。

数组本身就是可迭代的。但不仅仅是数组。字符串也可以迭代,很多其他内建对象也都可以迭代。

在核心 JavaScript 中,可迭代对象用途广泛。我们将会看到,很多内建的操作和方法都依赖于它。

Symbol.iterator

一个数据结构只要部署了Symbol.iterator属性就能使用 for...of遍历 与 ...运算符 操作

for of循环有很多优点,比如不像for...in一样只遍历键名(甚至包括原型链上的键),而且不像for each不能跳出循环。并且for...of为各种数据结构提供了一个统一的遍历方法。

es6中有三类结构生来就具有Iterator接口:数组、类数组对象、Map和Set结构。

对数组直接使用

let arr = [1,2,3,4];

console.log([...arr]);  //(4) [1, 2, 3, 4]

如果你需要对对象进行迭代操作,就需要手动给你的对象部署iterator接口咯~

通过自己创建一个可迭代对象,我们就可以很容易的掌握它的概念。

例如,我们有一个对象,它并不是数组,但是看上去很适合使用 for..of 循环。

比如一个 range 对象,代表了一个数字区间

为了让 range 对象可迭代(也就让 for..of 可以运行)我们需要为对象添加一个名为 Symbol.iterator 的方法(一个特殊的内置标记)。

  • 当 for..of 循环开始,它将会调用这个方法(如果没找到,就会报错)。
  • 这个方法必须返回一个迭代器 —— 一个有 next 方法的对象。
  • 当 for..of 循环希望取得下一个数值,它就调用这个对象的 next() 方法。
  • next() 返回结果的格式必须是 {done: Boolean, value: any},当 done=true 时,表示迭代结束,否则 value 必须是一个未被迭代的新值。

这是 range 的全部实现:

let range = {

  from: 1,

  to: 5

};

// 1. 使用 for..of 将会首先调用它:

range[Symbol.iterator] = function() {

  // 2. ...它返回一个迭代器:

  return {

    current: this.from,

    last: this.to,

    // 3. next() 将在 for..of 的每一轮循环迭代中被调用

    next() {

      // 4. 它将会返回 {done:.., value :...} 格式的对象

      if (this.current <= this.last) {

        return { done: false, value: this.current++ };

      } else {

        return { done: true };

      }

    }

  };

};

// 现在它可以运行了!

for (let num of range) {

  alert(num); // 1, 然后 2, 3, 4, 5

}

这段代码中有几点需要着重关注:

  • range 自身没有 next() 方法。
  • 相反,是调用 range[Symbol.iterator]() 时将会被创建的另一个所谓的“迭代器”对象,将会处理迭代操作。

所以,迭代器对象和迭代的对象其实是分离的。

字符串可迭代

数组和字符串是应用最广泛的内建可迭代对象。

对于一个字符串,for..of 循环它的每个字符(对于UTF-16 的扩展字符也能正常工作):

for (let char of "test") {

  alert( char ); // t,然后 e,然后 s,然后 t

}

显式调用迭代器

通常情况下,迭代器的内部函数对外部代码是隐藏的。for..of 循环可以工作,就是代码需要了解的所有内容了。

但是为了更深层的了解知识概念,我们来看看如何显式的创建迭代器。

我们将会采用与 for..of 一样的方法迭代字符串,但是是直接的调用。这段代码将会获取字符串的迭代器,然后“手动”调用它。

let str = "Hello";

// 和下面代码完成的功能一致

// for (let char of str) alert(char);

let iterator = str[Symbol.iterator]();

while (true) {

  let result = iterator.next();

  if (result.done) break;

  alert(result.value); // 一个一个输出字符

}




返回列表 返回列表
评论

    分享到