ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript ES6 のイテレータとジェネレータの概要

JavaScript ES6 のイテレータとジェネレータの概要

巴扎黑
巴扎黑オリジナル
2017-08-21 09:44:201096ブラウズ

この記事は主に ES6 のイテレーターとジェネレーターについて詳しく紹介しています。編集者が非常に優れていると考えたので、参考として共有します。エディターをフォローして見てみましょう

この記事では、ES6 のイテレーターとジェネレーターについて詳しく説明し、それらを共有します。詳細は次のとおりです:

ループ ステートメントの問題


var colors = ["red", "green", "blue"];
for(var i=0; i<colors.length; i++){
  console.log(colors[i]);
}

ES6 より前では、この標準の for ループは変数を通じて配列のインデックスを追跡します。複数のループがネストされている場合、複数の変数を追跡する必要があり、コードの複雑さが大幅に増加し、ループ変数の誤った使用によるバグが発生しやすくなります。

イテレーターは、この複雑さを取り除き、ループ内のエラーを減らすために導入されました。

イテレーターとは

まずは ES5 構文を使用してイテレーターの作成をシミュレートしてみましょう:


function createIterator(items) {
  var i = 0;
  
  return { // 返回一个迭代器对象
    next: function() { // 迭代器对象一定有个next()方法
      var done = (i >= items.length);
      var value = !done ? items[i++] : undefined;
      
      return { // next()方法返回结果对象
        value: value,
        done: done
      };
    }
  };
}

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

console.log(iterator.next()); // "{ value: 1, done: false}"
console.log(iterator.next()); // "{ value: 2, done: false}"
console.log(iterator.next()); // "{ value: 3, done: false}"
console.log(iterator.next()); // "{ value: undefiend, done: true}"
// 之后所有的调用都会返回相同内容
console.log(iterator.next()); // "{ value: undefiend, done: true}"

上記では、createIterator() 関数を呼び出してオブジェクトを返します。このオブジェクトにはnext() メソッドが呼び出されるとき、next() メソッドは、{value: 1、done: false} の形式で結果オブジェクトを返します。

したがって、次のように定義できます。イテレータは next() メソッドを持つ特別なオブジェクトであり、 next() が呼び出されるたびに結果オブジェクトが返されます。

この反復子オブジェクトの助けを借りて、最初に標準の for ループを変換します [ES6 の新しい for-of ループ機能については今は忘れてください]:


var colors = ["red", "green", "blue"];
var iterator = createIterator(colors);
while(!iterator.next().done){
  console.log(iterator.next().value);
}

何?、それは単にループ変数、大変手間がかかるのに、コード的には損してるんじゃないでしょうか?

実際はそうではありません。結局のところ、createIterator() は一度書くだけで済み、いつでも再利用できます。ただし、ES6 ではジェネレーター オブジェクトが導入されており、イテレーターの作成プロセスが簡単になります。

ジェネレーターとは

ジェネレーターは、関数キーワードの後に​​アスタリスク (*) で表され、関数内で新しいキーワード yield が使用されます。


function *createIterator(items) {
  for(let i=0; i<items.length; i++) {
    yield items[i];
  }
}

let iterator = createIterator([1, 2, 3]);

// 既然生成器返回的是迭代器,自然就可以调用迭代器的next()方法
console.log(iterator.next()); // "{ value: 1, done: false}"
console.log(iterator.next()); // "{ value: 2, done: false}"
console.log(iterator.next()); // "{ value: 3, done: false}"
console.log(iterator.next()); // "{ value: undefiend, done: true}"
// 之后所有的调用都会返回相同内容
console.log(iterator.next()); // "{ value: undefiend, done: true}"

上記では、イテレータの作成プロセスを大幅に簡素化する ES6 生成を使用しました。 items 配列をジェネレーター関数 createIterator() に渡します。関数内では、for ループが配列から新しい要素を継続的に生成し、ループが next ステートメントを呼び出すたびに停止します。 iterator () メソッドの場合、ループは実行を継続し、次の yield ステートメントで停止します。

ジェネレーターの作成方法

ジェネレーターは関数です:


function *createIterator(items) { ... }

は関数式モードで書くことができます:


let createIterator = function *(item) { ... }

はオブジェクトに追加することもできます、ES5スタイルのオブジェクトリテラル:


let o = {
  createIterator: function *(items) { ... }
};

let iterator = o.createIterator([1, 2, 3]);

ES6 スタイルのオブジェクトメソッドの略語:


let o = {
  *createIterator(items) { ... }
};

let iterator = o.createIterator([1, 2, 3]);

Iterable オブジェクト

ES6 では、すべてのコレクション オブジェクト (配列、Set コレクション、Map コレクション) と文字列は Iterable オブジェクトであり、反復可能オブジェクトはデフォルトのイテレータにバインドされます。

待望の新しい ES6 ループ機能 for-of:


var colors = ["red", "green", "blue"];
for(let color of colors){
  console.log(color);
}

for-of ループは、反復可能オブジェクトに適用でき、反復可能オブジェクト デバイスのデフォルトの反復を利用します。一般的なプロセスは次のとおりです。for-of ループが実行されるたびに、反復可能オブジェクトの next() メソッドが呼び出され、反復子によって返された結果オブジェクトの value 属性が変数に格納されます。ループは引き続き実行されます。このプロセスは、done オブジェクトが返されるまで続きます。

配列またはコレクション内の値を反復するだけの場合は、for ループの代わりに for-of ループを使用するのが良い選択です。

デフォルトのイテレータへのアクセス

Iterable オブジェクトには Symbol.iterator メソッドがあり、for-of ループが実行されると、colors 配列の Symbol.iterator メソッドを呼び出すことでデフォルトのイテレータが取得されます。エンジンは舞台裏で行われます。

このデフォルトのイテレータを取得してそれを感じさせることができます:


let values = [1, 2, 3];
let iterator = values[Symbol.iterator]();

console.log(iterator.next()); // "{ value: 1, done: false}"
console.log(iterator.next()); // "{ value: 2, done: false}"
console.log(iterator.next()); // "{ value: 3, done: false}"
console.log(iterator.next()); // "{ value: undefined, done: true}"

このコードでは、配列値のデフォルトのイテレータは Symbol.iterator を通じて取得され、要素内の要素を走査するために使用されます。配列。 JavaScript エンジンでの for-of ループ ステートメントの実行も同様のプロセスです。

オブジェクトが反復可能なオブジェクトかどうかを検出するには、Symbol.iterator プロパティを使用します。


function isIterator(object) {
  return typeof object[Symbol.iterator] === "function";
}

console.log(isIterable([1, 2, 3])); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(new Map())); // true
console.log(isIterable("Hello")); // true

反復可能なオブジェクトを作成します

オブジェクトを作成するときに、Symbol.iterator プロパティにジェネレーターを追加します。それを反復可能なオブジェクトに変えることができます:


let collection = {
  items: [],
  *[Symbol.iterator]() { // 将生成器赋值给对象的Symbol.iterator属性来创建默认的迭代器
    for(let item of this.items) {
      yield item;
    }
  }
};

collection.items.push(1);
collection.items.push(2);
collection.items.push(3);

for(let x of collection) {
  console.log(x);
}

組み込みイテレータ

ES6 の Collection オブジェクト、配列、Set コレクション、Map コレクションには、すべて 3 つの組み込みイテレータがあります:

  • entries () 値が複数のキーと値のペアであるイテレータを返します。配列の場合、最初の要素はインデックス位置です。セットの場合、最初の要素と 2 番目の要素は両方とも値です。

  • values() は、値がコレクションの値である反復子を返します。

  • keys() は、コレクション内のすべてのキー名を値とする反復子を返します。配列の場合はインデックスが返され、セットの場合は値が返されます (セットの値はキーと値の両方として使用されます)。

不同集合的默认迭代器

每个集合类型都有一个默认的迭代器,在for-of循环中,如果没有显式指定则使用默认的迭代器。按常规使用习惯,我们很容易猜到,数组和Set集合的默认迭代器是values(),Map集合的默认迭代器是entries()。

请看以下示例:


let colors = [ "red", "green", "blue"];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();

data.set("title", "Understanding ECMAScript 6");
data.set("format", "print");

// 与调用colors.values()方法相同
for(let value of colors) {
  console.log(value);
}

// 与调用tracking.values()方法相同
for(let num of tracking) {
  console.log(num);
}

// 与调用data.entries()方法相同
for(let entry of data) {
  console.log(entry);
}

这段代码会输入以下内容:

"red"
"green"
"blue"
1234
5678
9012
["title", "Understanding ECMAScript 6"]
["format", "print"]

for-of循环配合解构特性,操纵数据会更方便:


for(let [key, value] of data) {
  console.log(key + "=" + value);
}

展开运算符操纵可迭代对象


let set = new Set([1, 2, 3, 4, 5]),
  array = [...set];
  
console.log(array); // [1,2,3,4,5]

展开运算符可以操作所有的可迭代对象,并根据默认迭代器来选取要引用的值,从迭代器读取所有值。然后按返回顺序将它们依次插入到数组中。因此如果想将可迭代对象转换为数组,用展开运算符是最简单的方法。

以上がJavaScript ES6 のイテレータとジェネレータの概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。