ホームページ  >  記事  >  ウェブフロントエンド  >  ES6 のイテレータと反復可能オブジェクトの原理の紹介 (例付き)

ES6 のイテレータと反復可能オブジェクトの原理の紹介 (例付き)

不言
不言転載
2018-10-29 15:34:362624ブラウズ

この記事では、ES6 のイテレータと反復可能なオブジェクトの概要を紹介します (例を示します)。必要な方は参考にしていただければ幸いです。

ES6 の新しい配列メソッド、コレクション、for-of ループ、スプレッド演算子 (...)、さらには非同期プログラミングはすべて反復子 (Iterator) の実装に依存しています。この記事では、ES6 のイテレータとジェネレータについて詳しく説明し、反復可能なオブジェクトの内部原理と使用法をさらに詳しく説明します

#1 イテレータの原理#プログラミング言語での配列の処理。ループ ステートメントまたはコレクションを使用する場合は、変数を初期化して反復位置を記録する必要があります。プログラムで反復子を使用すると、このデータ操作を簡素化できます。

反復子の設計方法。

イテレータ自体はオブジェクトです。このオブジェクトには、結果オブジェクトを返す next() メソッドがあり、次の戻り値と反復完了のブール値がシミュレートされます。単純なイテレータの作成は次のとおりです:

function createIterator(iterms) {
  let i = 0
  return {
    next() {
      let done = (i >= iterms.length)
      let value = !done ? iterms[i++] : undefined
      return {
        done,
        value
      }
    }
  }
}

let arrayIterator = createIterator([1, 2, 3])

console.log(arrayIterator.next()) // { done: false, value: 1 }
console.log(arrayIterator.next()) // { done: false, value: 2 }
console.log(arrayIterator.next()) // { done: false, value: 3 }
console.log(arrayIterator.next()) // { done: true, value: undefined }
上記の構文について混乱している場合は、次を参照してください:

ES6 の新しい関数とオブジェクトの構造化割り当ての詳細な説明 (コード例)

イテレータの next() が呼び出されるたびに、データセットがなくなるまで次のオブジェクトを返します。

ES6 でのイテレータの作成ルールは似ていますが、イテレータ オブジェクトの作成を容易にするためにジェネレータ オブジェクトが導入されています。

2 イテレータの作成

ES6 はジェネレータをカプセル化してイテレータを作成します。明らかに、ジェネレーターは、関数の後のアスタリスク (*) で表される反復子を返す関数であり、新しい内部特殊キーワード yield を使用して反復子の next() メソッドの戻り値を指定します。

ES6 ジェネレーターを使用してイテレーターを作成するにはどうすればよいですか?簡単な例は次のとおりです。

function *createIterator() {
  yield 123;
  yield 'someValue'
}

let someIterator = createIterator()

console.log(someIterator.next()) // { value: 123, done: false }
console.log(someIterator.next()) // { value: 'someValue', done: false }
console.log(someIterator.next()) // { value: undefined, done: true }

yield キーワードを使用して任意の値または式を返すと、反復子に要素をバッチで追加できます。

// let createIterator = function *(items) { // 生成器函数表达式
function *createIterator(items) {
  for (let i = 0; i < items.length; i++) {
    yield items[i]
  }
}

let someIterator = createIterator([123, &#39;someValue&#39;])

console.log(someIterator.next()) // { value: 123, done: false }
console.log(someIterator.next()) // { value: &#39;someValue&#39;, done: false }
console.log(someIterator.next()) // { value: undefined, done: true }

ジェネレーター自体は関数であるため

これはオブジェクトに追加でき、次のように使用されます。

let obj = {
  // createIterator: function *(items) { // ES5
  *createIterator(items) { // ES6
    for (let i = 0; i < items.length; i++) {
      yield items[i]
    }
  }
}
let someIterator = obj.createIterator([123, &#39;someValue&#39;])
ジェネレーター関数の 1 つの特徴は、関数が yield ステートメントの実行後に実行を自動的に停止し、イテレーターの next() メソッドが次の yield ステートメントの実行を継続するために再度呼び出されます。

関数の実行を自動的に終了するこの機能は、多くの高度な用途につながりました。

3. 反復可能なオブジェクト

ES6 で一般的に使用されるコレクション オブジェクト (配列、Set/Map コレクション) と文字列は反復可能なオブジェクトであり、これらのオブジェクトにはデフォルトの反復子とシンボルがあります。イテレータプロパティ。

ジェネレーターはデフォルトで Symbol.iterator プロパティに値を割り当てるため、ジェネレーターによって作成されたイテレーターも反復可能オブジェクトです。

3.1 Symbol.iterator

Iterable オブジェクトには Symbol.iterator プロパティがあります。つまり、Symbol.iterator プロパティを持つオブジェクトにはデフォルトのイテレータがあります。

Symbol.iterator を使用して、オブジェクト (配列など) のデフォルトのイテレータにアクセスできます。

let list = [11, 22, 33]
let iterator = list[Symbol.iterator]()
console.log(iterator.next()) // { value: 11, done: false }

Symbol.iterator は、配列の反復可能なオブジェクトのデフォルトのイテレータを取得し、配列内の要素を反復処理します。

逆に、Symbol.iterator を使用して、オブジェクトが反復可能なオブジェクトかどうかを検出できます。

function isIterator(obj) {
  return typeof obj[Symbol.iterator] === &#39;function&#39;
}

console.log(isIterator([11, 22, 33])) // true
console.log(isIterator(&#39;sometring&#39;)) // true
console.log(isIterator(new Map())) // true
console.log(isIterator(new Set())) // true
console.log(isIterator(new WeakMap())) // false
console.log(isIterator(new WeakSet())) // false

明らかに、配列、Set/Map コレクション、文字列はすべて反復可能なオブジェクトであり、WeakSet /WeakMap コレクション (弱い参照コレクション) は反復可能ではありません。

3.2 反復可能なオブジェクトの作成

デフォルトでは、カスタム オブジェクトは反復可能ではありません。

先ほど述べたように、ジェネレーターによって作成されたイテレーターも反復可能なオブジェクトであり、ジェネレーターはデフォルトで Symbol.iterator プロパティに値を割り当てます。

では、カスタム オブジェクトを反復可能なオブジェクトに変えるにはどうすればよいでしょうか? Symbol.iterator プロパティにジェネレーターを追加します。

let collection = {
  items: [11,22,33],
  *[Symbol.iterator]() {
    for (let item of this.items){
      yield item
    }
  }
}

console.log(isIterator(collection)) // true

for (let item of collection){
  console.log(item) // 11 22 33
}

配列項目は反復可能オブジェクトであり、Symbol.iterator プロパティに値を割り当てることでコレクション オブジェクトも反復可能オブジェクトになります。

3.3 for-of

最後の栗は、インデックス ループの代わりに for-of を使用していることに注意してください。for-of は、反復可能なオブジェクト用に ES6 によって追加された新機能です。

for-of ループの実装原理を考えてみましょう。

for-of を使用する反復可能オブジェクトの場合、for-of が実行されるたびに、反復可能オブジェクトの next() が呼び出され、戻り結果が変数に格納され、反復可能オブジェクトが終了するまで実行が継続されます。オブジェクトのdone属性値はfalseです。

// 迭代一个字符串
let str = &#39;somestring&#39;

for (let item of str){
  console.log(item) // s o m e s t r i n g
}

基本的に、for-of は str 文字列の Symbol.iterator プロパティ メソッドを呼び出してイテレータを取得し (このプロセスは JS エンジンによって完了します)、次に next() メソッドを複数回呼び出して保存します。 item 変数のオブジェクト値。

反復不可能なオブジェクトに for-of を使用すると、null または未定義の場合、エラーが報告されます。

3.4 展開演算子 (...)

ES6 構文のシュガー展開演算子 (...) も反復可能なオブジェクトを処理します。つまり、配列とコレクションのみを「展開」できます。 、文字列、カスタム反復可能オブジェクト。

次の例は、さまざまな反復可能オブジェクト展開演算子によって計算された結果を出力します。

let str = &#39;somestring&#39;
console.log(...str) // s o m e s t r i n g
let set = new Set([1, 2, 2, 5, 8, 8, 8, 9])
console.log(set) // Set { 1, 2, 5, 8, 9 }
console.log(...set) // 1 2 5 8 9
let map = new Map([[&#39;name&#39;, &#39;jenny&#39;], [&#39;id&#39;, 123]])
console.log(map) // Map { &#39;name&#39; => 'jenny', 'id' => 123 }
console.log(...map) // [ 'name', 'jenny' ] [ 'id', 123 ]
let num1 = [1, 2, 3], num2 = [7, 8, 9]
console.log([...num1, ...num2]) // [ 1, 2, 3, 7, 8, 9 ]
let udf
console.log(...udf) // TypeError: undefined is not iterable
上記のコードからわかるように、展開演算子 (...) は反復可能オブジェクトを簡単に変換できます。配列。 for-of と同様に、スプレッド演算子 (...) を反復不可能なオブジェクト (null または未定義) で使用すると、エラーが報告されます。

4. デフォルトのイテレータ

ES6 为很多内置对象提供了默认的迭代器,只有当内建的迭代器不能满足需求时才自己创建迭代器。

ES6 的 三个集合对象:Set、Map、Array 都有默认的迭代器,常用的如values()方法、entries()方法都返回一个迭代器,其值区别如下:

entries():多个键值对

values():集合的值

keys():集合的键

调用以上方法都可以得到集合的迭代器,并使用for-of循环,示例如下:

/******** Map ***********/
let map = new Map([['name', 'jenny'], ['id', 123]])

for(let item of map.entries()){
  console.log(item) // [ 'name', 'jenny' ]  [ 'id', 123 ]
}
for(let item of map.keys()){
  console.log(item) // name id
}
for (let item of map.values()) {
  console.log(item) // jenny 123
}

/******** Set ***********/
let set = new Set([1, 4, 4, 5, 5, 5, 6, 6,])

for(let item of set.entries()){
  console.log(item) // [ 1, 1 ] [ 4, 4 ] [ 5, 5 ] [ 6, 6 ]
}

/********* Array **********/
let array = [11, 22, 33]

for(let item of array.entries()){
  console.log(item) // [ 0, 11 ] [ 1, 22 ] [ 2, 33 ]
}

此外 String 和 NodeList 类型都有默认的迭代器,虽然没有提供其它的方法,但可以用for-of循环

以上がES6 のイテレータと反復可能オブジェクトの原理の紹介 (例付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。