ES6 - イテレータ イテレータと for...of ループ

ここに画像の説明を挿入

序文

JavaScript 本来の「コレクション」を表すデータ構造は主に配列(Array)とオブジェクト(Object)ですが、ES6 では と が追加されましMapSetユーザーはこれらを組み合わせて使用​​して独自のデータ構造を定義することもできます。たとえば、配列のメンバーは object でありMapMap配列のメンバーはオブジェクトです。これには、さまざまなデータ構造をすべて処理するための統一されたインターフェイス メカニズムが必要です。

1. イテレータの概要

イテレータとはそのような仕組みです。これは、さまざまなデータ構造に対する統合アクセス メカニズムを提供するインターフェイスです。データ構造が Iterator インターフェイスをデプロイしている限り、トラバーサル操作を完了できます (つまり、データ構造のすべてのメンバーを順番に処理します)。

Iterator には 3 つの機能があります: 1 つはさまざまなデータ構造に統一された便利なアクセス インターフェイスを提供すること、もう 1 つはデータ構造のメンバーを特定の順序で配置できるようにすること、3 つ目は ES6 が新しいトラバーサル コマンド ループを作成することですfor...of。 , Iterator インターフェイスは主にfor...of消費用です。

2、反復子の原則

Iterator の直訳は、任意の反復可能なデータ型のデータを反復処理できる反復子であり、データを反復処理できる反復可能データのインターフェイス メカニズムを提供します。

一般に、関数の next メソッドを使用してデータを反復し、データが存在する場合はオブジェクトを返します{value :数据, done : false}

「データがありません」という場合は、オブジェクトを返します。{value : undefined , done : true}

したがって、反復子を使用する前に、データが反復を開始する場所を指すポインターを定義する必要があります。初期ポインターは 0 番目の要素を指します。

次の場合のように:


function makeIterator(array) {
    
    
  var nextIndex = 0;
  return {
    
     // 注意:此处使用了闭包,nextIndex会被一直引用,也就是会被下面一直累加;
    next: function() {
    
    
       // 注意:此处判断结束条件  当前长度是否小于数组的总长度
       // 小于说明未运行结束  不小于说明改结束了
      return nextIndex < array.length ?
        {
    
    value: array[nextIndex++], done: false} :
        {
    
    value: undefined, done: true};
    }
  };
}

var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

Iterator の走査プロセスは次のとおりです。

(1) 現在のデータ構造の開始位置を指すポインター オブジェクトを作成します。言い換えれば、トラバーサー オブジェクトは本質的にはポインター オブジェクトです。

(2) ポインター オブジェクトのメソッドが初めて呼び出されnext、ポインターはデータ構造の最初のメンバーを指すことができます。

(3) ポインター オブジェクトのメソッドが 2 回目に呼び出されるときnext、ポインターはデータ構造の 2 番目のメンバーを指します。

(4)nextデータ構造の終端を指すまでポインタ オブジェクトのメソッドを呼び出し続けます。

nextメソッドが呼び出されるたびに、データ構造の現在のメンバーに関する情報が返されます。value具体的には、と2 つのプロパティを含むオブジェクトを返しますdoneこのうち、value属性は現在のメンバーの値であり、done属性は走査が終了したかどうかを示すブール値です。

3. Iterator インターフェイスを実装するネイティブ オブジェクトは次のとおりです。

ES6 では、デフォルトの Iterator インターフェイスがデータ構造の Symbol.iterator プロパティにデプロイされることが規定されています。つまり、データ構造に Symbol.iterator プロパティがある限り、データ構造は通過可能であると見なされます。

Iterator インターフェイスをネイティブに持つデータ構造は次のとおりです。

  • 配列
  • 地図
  • セット
  • 型付き配列
  • 関数の引数オブ​​ジェクト
  • NodeList オブジェクト

Array プロトタイプ オブジェクトと Set コレクションに Iterator プロパティが実装されていることがわかります。

  // 数组
  console.log("array:",Array.prototype);
  // Es6新增Set集合
  let set = new Set([1, 2, 3]);
  console.log("set:",set);

次の図を出力します。
ここに画像の説明を挿入
すると、次のように、配列のインスタンス オブジェクトにも当然このプロパティが設定されます。

      let arrIter = [1, 2, 3][Symbol.iterator]();
      console.log("arrIter:", arrIter);
      console.log(arrIter.next());
      console.log(arrIter.next());
      console.log(arrIter.next());
      console.log(arrIter.next());

ここに画像の説明を挿入

5. Iteratorインターフェースがデフォルトで呼び出される場合

場合によっては、Iterator インターフェイス (つまり、メソッド) がデフォルトで呼び出されます。Symbol.iterator以下で説明するfor...ofループに加えて、他にもいくつかの場合があります。

(1) 代入の分割

配列および Set 構造体への代入を分割する場合、Symbol.iteratorデフォルトでこのメソッドが呼び出されます。

let set = new Set().add('a').add('b').add('c');

let [x,y] = set;
// x='a'; y='b'

let [first, ...rest] = set;
// first='a'; rest=['b','c'];

(2) スプレッド演算子

スプレッド演算子 (…) もデフォルトの Iterator インターフェイスを呼び出します。

// 例一
var str = 'hello';
[...str] //  ['h','e','l','l','o']

// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']

実際、これは、Iterator インターフェイスを実装するデータ構造を配列に変換する便利なメカニズムを提供します。つまり、データ構造が Iterator インターフェイスを実装している限り、スプレッド演算子を使用して配列に変換できます。

let arr = [...iterable];

(3)収量*

yield*続いてトラバース可能な構造体が続き、その構造体のトラバーサー インターフェイスが呼び出されます。

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

var iterator = generator();

iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }

(4) その他の機会

配列のトラバーサルはトラバーサー インターフェイスを呼び出すため、配列をパラメーターとして受け入れる場合は実際にトラバーサー インターフェイスを呼び出します。以下にいくつかの例を示します。

  • Array.from()
  • Map()、Set()、WeakMap()、WeakSet() (例new Map([['a',1],['b',2]]))
  • Promise.all()
  • Promise.race()

ループの 6、for...

for... of循环其实就是 Iterator 的语法糖

for...of ループが使用できるスコープには、配列、Set および Map 構造体、一部の配列のようなオブジェクト (引数オブジェクト、DOM NodeList オブジェクトなど)、文字列などが含まれます。つまり、Iterator インターフェイスを持つデータ型は for ...of; によってトラバースできます。

(一般的なオブジェクトは走査できず、エラーが直接報告されます。obj は反復可能ではありません)

配列にはネイティブに反復子インターフェイスがあり (Symbol.iterator プロパティがデフォルトでデプロイされます)、for...of 循环本质上これはこのインターフェイスを呼び出すことによって生成されるトラバーサーです。

for...of は次のように使用されます。

      
	  ## 1,遍历数组 
	  let arr = [{
    
    name:'Eula',age:20},{
    
    name:'Kaya',age:20}]
      for (const iterator of arr) {
    
    
        console.log("iterator:",iterator); // {name: 'Eula', age: 20}  {name: 'Kaya', age: 20}
      }

	  ## 2,遍历字符串 
      let str = "hello"
      for (const iterator of str) {
    
    
        console.log("iterator:",iterator); // 'h' 'e' 'l'' l'' o'
      }

	  ## 3,遍历set集合
      let set = new Set([{
    
    name:'Eula',age:20},{
    
    name:'Kaya',age:20}])
      for (const iterator of set) {
    
    
        console.log("iterator:",iterator); // {name: 'Eula', age: 20}  {name: 'Kaya', age: 20}
      }

	  ## 4,遍历map集合
      let map = new Map()
      map.set('name','Eula')
      map.set('age','18')
      console.log("map:",map); // Map(2) {'name' => 'Eula', 'age' => '18'}
      for (const iterator of map) {
    
    
        console.log("iterator:",iterator); //  ['name', 'Eula']  ['age', '18']
      }

通常のオブジェクトを反復処理する場合は、for in ループを使用できます。

      let obj = {
    
    name:'Eula'}
      for (const iterator in obj) {
    
    
        console.log("键:",iterator); // name
        console.log("值:",obj[iterator]);  // Eula
      }

七、概要

  1. データ構造のプロトタイプに属性がある限りSymbol.iterator、それは走査可能であるとみなされます。
  2. for...of ループは実際には Iterator の糖衣構文です。

おすすめ

転載: blog.csdn.net/qq_43886365/article/details/132018581