[译]JavaScript ES6迭代器指南

媒介

EcmaScript 2015 (又称ES6)供应一个全新的迭代器的观点,它许可我们在言语层面上定义一个(有限或无穷的)序列。

临时先抛开它。我们关于for轮回以及它的兄弟for-in轮回,都已非常的熟习。后者能够被用来协助我们明白迭代器。

jsfor (var key in table) {
  console.log(key + ' = ' + table[key]);
}

关于for-in轮回,它有很多的题目。然则最大的题目,就是它不保证迭代的递次。然则当我们运用ES6迭代器时,这个题目就水到渠成了。

for-of

for-of是ES6中的新语法,用来合营迭代器。

jsfor (var key of table) {
  console.log(key + ' = ' + table[key]);
}

运用for-of,我们获得的是一个能够保证递次的迭代。为了让一个对象能够被迭代器所迭代,对象须要完成一个“迭代协定”,即具有一个Symbol.iterator属性。这个属性会被for-of所运用,在我们的例子中,它就是table[Symbol.iterator]

Symbol.iterator也是在ES6中新增的内容,我们会在另一篇文章中细致议论。在这里,我们只需以为它是对象的一个特别属性,而且永久不会和其他一般属性发生争执。

table[Symbol.iterator]的值,必需是一个相符“迭代协定”的函数,即它须要返回一个类似于{ next: function () {} }的对象。

jstable[Symbol.iterator] = function () {
   return {
    next: function () {}
  }
}

然后,在for-of轮回每次挪用next()函数时,它须要返回一个类似于{value: …, done: [true/false]}的对象。所以,一个迭代器的完全完成类似于以下的例子:

jstable[Symbol.iterator] = function () {
  var keys = Object.keys(this).sort();
  var index = 0;

  return {
    next: function () {
      return {
        value: keys[index], done: index++ >= keys.length
      };
    }
  }
}

惰性实行

迭代器许可我们在第一次挪用next()函数以后,再实行响应的逻辑。在上面的例子里,当我们挪用迭代器的霎时,我们就马上实行了排序和取值的事情。然则,假如next()函数永久不被挪用的话,我们就浪费了机能。所以让我们来优化它:

jstable[Symbol.iterator] = function () {
  var _this = this;
  var keys = null;
  var index = 0;

  return {
    next: function () {
      if (keys === null) {
        keys = Object.keys(_this).sort();
      }

      return {
        value: keys[index], done: index++ >= keys.length
      };
    }
  }
}

for-offor-in的差异

明白for-offor-in之间的差异,是非常重要的。以下是一个简朴的,然则非常好的诠释差异的例子:

jsvar list = [3, 5, 7];
list.foo = 'bar';

for (var key in list) {
  console.log(key); // 0, 1, 2, foo
}

for (var value of list) {
  console.log(value); // 3, 5, 7
}

正如所见的,for-of轮回仅打印出了数组中的值,疏忽了其他属性。这是由于数组的迭代器只返回个中预期的元素。

内置迭代器

StringArrayTypedArrayMapSet都是内置迭代器,由于它们的原型中都有一个Symbol.iterator要领。

jsvar string = "hello";

for (var chr of string) {
  console.log(chr); // h, e, l, l, o
}

解构赋值

解构操纵一样也接收一个迭代器:

jsvar hello = 'world';
var [first, second, ...rest] = [...hello];
console.log(first, second, rest); // w o ["r","l","d"]

无穷迭代器

只需永久不返回done: true,就完成了一个无穷迭代器。固然,须要尽力防止涌现这类状况。

jsvar ids = {
  *[Symbol.iterator]: function () {
    var index = 0;

    return {
      next: function () {
        return { value: 'id-' + index++, done: false };
      }
    };
  }
};

var counter = 0;

for (var value of ids) {
  console.log(value);

  if (counter++ > 1000) { // let's make sure we get out!
    break;
  }
}

Generator函数

假如你还不相识ES6 generator 函数,请参考MDN文档。简而言之,generator函数是当前被议论最多的ES6特征,它是一个能够临时退出,而且稍后从新进入继承实行的函数。在屡次的进入中,它的上下文(绑定的变量)是会被保留的。generator函数本身就是一个迭代器,来看下面的例子:

jsfunction* list(value) {
  for (var item of value) {
    yield item;
  }
}

for (var value of list([1, 2, 3])) {
  console.log(value);
}

var iterator = list([1, 2, 3]);

console.log(typeof iterator.next); // function
console.log(typeof iterator[Symbol.iterator]); // function

console.log(iterator.next().value); // 1

for (var value of iterator) {
  console.log(value); // 2, 3
}

所以,我们能够运用generator函数重写我们上面的迭代器:

jstable[Symbol.iterator] = function* () {
  var keys = Object.keys(this).sort();

  for (var item of keys) {
    yield item;
  }
}

末了

迭代器给JavaScript中的轮回,generator函数和值序列(value series)带来了一个新的维度。你能够运用它,定义一个类中,它的值的排序体式格局,也能够用经由过程其来建立一个惰性的或无穷的序列,等等。

原文地点

https://strongloop.com/strongblog/introduction-to-es6-iterators/

    原文作者:菜菜蔡伟
    原文地址: https://segmentfault.com/a/1190000003021261
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞