インタラクティブ-34


イテレーションプロトコル


ES 6に導入された反復プロトコル(iteration protocol)は、ECMAScript仕様で定義された、反復可能なデータ構造を作成するための予め定められた規則である.
ES 6以前の循環可能なデータセット、すなわち配列、文字列、類似配列オブジェクト、DOMセットは、forゲート、for...inゲート、forEachゲート、for...ofゲートを含む異なる方法で巡回することができる.
ES 6は、循環可能なデータセットを、Symbol.iterator文、スプレッドシート構文、配列構造分解割当のオブジェクトに使用できる、イテレーションプロトコルに準拠するイテレーションに統一する.
イテレーションプロトコルには、イテレーションプロトコルとイテレーションプロトコルがあります.
1.移植可能プロトコル(iterable protocol)

  • Wellが既知のSymbol Symbol.iteratorをプロトコル鍵として使用する方法を直接実装するか、またはプロトコルタイプチェーンによって継承されたfor...ofの方法を呼び出すと、ウィジェットプロトコルに準拠するウィジェットが返される.これらの約束を移植可能プロトコルと呼ぶ.

  • プログラマブルプロトコルを遵守するオブジェクトをプログラマブルオブジェクトと呼ぶ.これは、Symbol.iterator文、スプレッドシート構文、配列構造分解割当に使用できます.
  • 2.ウィジェットプロトコル(反復プロトコル)

  • ウィジェットを呼び出すnextメソッドは、ウィジェットプロトコルを遵守するウィジェットを返す.イテレーションにはnextメソッドがあり、valueメソッドを呼び出すと、doneメソッドとArray.prototype propertyを持つイテレーションオブジェクトが返されます.

  • これらの約束を小プログラムプロトコルと呼び,小プログラムプロトコルを遵守する対象を小プログラムと呼ぶ.ウィジェットは、ウィジェット要素のポインタをナビゲートする役割を果たします.
  • こわれやすい


  • プログラマブルプロトコルを遵守するオブジェクトをプログラマブルオブジェクトと呼ぶ.

  • 例えば、配列はSymbol.iteratorfor...ofメソッドを継承する小さな可愛さである.Symbol.iteratorゲートを巡回することができ、スプレッドシート構文および配列解析割り当てに使用することができる.
  • const array = [1, 2, 3];
    
    // 배열은 Array.prototype의 Symbol.iterator 메서드를 상속받는 이터러블이다.
    console.log(Symbol.iterator in array); // true
    
    // 이터러블인 배열은 for...of 문으로 순회 가능하다.
    for (const item of array) {
      console.log(item);
    }
    
    // 이터러블인 배열은 스프레드 문법의 대상으로 사용할 수 있다.
    console.log([...array]); // [1, 2, 3]
    
    // 이터러블인 배열은 배열 디스트럭처링 할당의 대상으로 사용할 수 있다.
    const [a, ...rest] = array;
    console.log(a, rest); // 1, [2, 3]
    
  • 2for...ofメソッドを直接実装または継承しない一般的なオブジェクトは、移植可能プロトコルを遵守する移植可能なオブジェクトではない.したがって,一般オブジェクトはSymbol.iterator文で巡回することはできず,スプレッドシート構文と解析的割当てを同時に使用することはできない.
  • const obj = { a: 1, b: 2 };
    
    // 일반 객체는 Symbol.iterator 메서드를 구현하거나 상속받지 않는다.
    // 따라서 일반 객체는 이터러블 프로토콜을 준수한 이터러블이 아니다.
    console.log(Symbol.iterator in obj); // false
    
    // 이터러블이 아닌 일반 객체는 for...of 문으로 순회할 수 없다.
    for (const item of obj) { // -> TypeError: obj is not iterable
      console.log(item);
    }
    
    // 이터러블이 아닌 일반 객체는 배열 디스트럭처링 할당의 대상으로 사용할 수 없다.
    const [a, b] = obj; // -> TypeError: obj is not iterable
    
  • セグメントは、TC 39プロセスの第4フェーズ(完了)フェーズで提案されたスプレッドシート推奨で、通常のオブジェクトのスプレッドシート構文を使用することができる.
  • const obj = { a: 1, b: 2 };
    
    // 스프레드 프로퍼티 제안(Stage 4)은 객체 리터럴 내부에서 스프레드 문법의 사용을 허용한다.
    console.log({ ...obj }); // { a: 1, b: 2 }
    
  • しかし、一般オブジェクトもウィジェットプロトコルを遵守することを実現すれば、それはウィジェットになる.これについては、後で検討します.
  • イテレーション


    ウィジェットを呼び出すSymbol.iteratorメソッドは、ウィジェットプロトコルを遵守するウィジェットを返す.このウィジェットのnextメソッドが返すウィジェットは、nextメソッドを有する.
    // 배열은 이터러블 프로토콜을 준수한 이터러블이다.
    const array = [1, 2, 3];
    
    // Symbol.iterator 메서드는 이터레이터를 반환한다.
    const iterator = array[Symbol.iterator]();
    
    // Symbol.iterator 메서드가 반환한 이터레이터는 next 메서드를 갖는다.
    console.log('next' in iterator); // true
    
  • ウィジェットのnextメソッドは、ウィジェットの各要素を遍歴するためのポインタとして機能する.すなわち、nextメソッドが呼び出されると、ウィジェットは順次巡回され、ループ結果を表すウィジェットツリーオブジェクト(iterator result object)が返される.
  • // 배열은 이터러블 프로토콜을 준수한 이터러블이다.
    const array = [1, 2, 3];
    
    // Symbol.iterator 메서드는 이터레이터를 반환한다. 이터레이터는 next 메서드를 갖는다.
    const iterator = array[Symbol.iterator]();
    
    // next 메서드를 호출하면 이터러블을 순회하며 순회 결과를 나타내는 이터레이터 리절트 객체를
    // 반환한다. 이터레이터 리절트 객체는 value와 done 프로퍼티를 갖는 객체다.
    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 }
    
  • ウィジェットのvalueメソッドが返すウィジェットセクションオブジェクトのdoneは、現在巡回中のウィジェットの値を表し、Array, String, Map, Set, TypedArray, arguments, DOM 컬렉션は、そのウィジェットが巡回を完了したか否かを表す.
  • ビルド可能


  • JSは、イテレーションプロトコルに準拠するオブジェクトの構築反復を提供します.
  • for...of
  • for...ドアの

  • for...ofゲートは、反復を巡回しながら、反復の要素を変数に割り当てます.for...inゲートはfor...inゲートと非常に類似している.
  • [[Enumberable]]ゲートオブジェクトのプロトタイプチェーン上に存在するすべてのプロトタイプのプロトタイプのうち、プロトタイプツリーtrueの値がfor...ofのプロトタイプが巡回してリストされる.この場合、プロ選手のキーはリストされません.
  • next文の内部には、ウィジェットのnextメソッドが呼び出され、valueメソッドが返すウィジェットツリーオブジェクトのfor...of値は、done文の変数に割り当てられる.また、falseの価格がtrueであれば、交換可能なツアーが継続され、for...ofが停止する.
  • for (const item of [1, 2, 3]) {
      // item 변수에 순차적으로 1, 2, 3이 할당된다.
      console.log(item); // 1 2 3
    }
    
  • 以上のコードのfor文の内部動作はSymbol.iterator文で以下のように表現される.
  • // 이터러블
    const iterable = [1, 2, 3];
    
    // 이터러블의 Symbol.iterator 메서드를 호출하여 이터레이터를 생성한다.
    const iterator = iterable[Symbol.iterator]();
    
    for (;;) {
      // 이터레이터의 next 메서드를 호출하여 이터러블을 순회한다. 이때 next 메서드는 이터레이터 리절트 객체를 반환한다.
      const res = iterator.next();
    
      // next 메서드가 반환한 이터레이터 리절트 객체의 done 프로퍼티 값이 true이면 이터러블의 순회를 중단한다.
      if (res.done) break;
    
      // 이터레이터 리절트 객체의 value 프로퍼티 값을 item 변수에 할당한다.
      const item = res.value;
      console.log(item); // 1 2 3
    }
    

    小さなかわいい配列オブジェクトに似ています

    // 유사 배열 객체
    const arrayLike = {
      0: 1,
      1: 2,
      2: 3,
      length: 3
    };
    
    // 유사 배열 객체는 length 프로퍼티를 갖기 때문에 for 문으로 순회할 수 있다.
    for (let i = 0; i < arrayLike.length; i++) {
      // 유사 배열 객체는 마치 배열처럼 인덱스로 프로퍼티 값에 접근할 수 있다.
      console.log(arrayLike[i]); // 1 2 3
    }
    
  • 類似配列オブジェクトは、小さなかわいいオブジェクトではなく、普通のオブジェクトです.したがって,類似配列のオブジェクトはfor...ofメソッドがないため,arguments, NodeList, HTMLCollectionゲートで巡回することはできない.
  • // 유사 배열 객체는 이터러블이 아니기 때문에 for...of 문으로 순회할 수 없다.
    for (const item of arrayLike) {
      console.log(item); // 1 2 3
    }
    // -> TypeError: arrayLike is not iterable
    

  • しかし、Symbol.iteratorは似たような配列の対象であり、同時にかわいい.

  • 同様に,アレイもES 6に反復を導入し,arrayLike法を実現し,反復となった.

  • 上記の例のArray.fromオブジェクトは、類似した配列のオブジェクトであるが、小さくてかわいいものではない.しかし、ES 6によって導入されたArray.from法を使用して簡単にアレイに変換することができる.
  • for...ofメソッドは、類似配列オブジェクトまたは小可愛さを引数として受け入れ、配列に変換して返します.
  • // 유사 배열 객체
    const arrayLike = {
      0: 1,
      1: 2,
      2: 3,
      length: 3
    };
    
    // Array.from은 유사 배열 객체 또는 이터러블을 배열로 변환한다
    const arr = Array.from(arrayLike);
    console.log(arr); // [1, 2, 3]
    

    イテレーションプロトコルが必要


  • 以上のように、fibonacci文、スプレッドシート構文、配列構造などのデータ消費者(データ使用者)によって使用されるため、データプロバイダと言える.

  • 異なるデータプロバイダがそれぞれの巡回方式を持っている場合、データ消費者はすべての異なるデータプロバイダの巡回方式をサポートしなければならない.これは非効率です.

  • ただし、異なるデータプロバイダがイテレーションプロトコルを遵守することを規定する場合、データ消費者はイテレーションプロトコルをサポートするだけでよい.

  • この小バージョンプロトコルは、異なるデータプロバイダが、データ消費者とプロバイダを接続するインタフェースとして、異なるデータプロバイダを効率的に使用することができるポーリング方式を規定している.(p.621図参照-より分かりやすい)
  • カスタムかわいい


    カスタムかわいいの実装


  • スモール・ラベル・プロトコルを遵守しない通常のオブジェクトが、スモール・バージョン・プロトコルを遵守するように実装されると、カスタム・スモール・ラベルになります.

  • フィボナッチ数列を実現した簡単なカスタムかわいいを実現しましょう.
  • // 피보나치 수열을 구현한 사용자 정의 이터러블
    const fibonacci = {
      // Symbol.iterator 메서드를 구현하여 이터러블 프로토콜을 준수한다.
      [Symbol.iterator]() {
        let [pre, cur] = [0, 1]; // "36.1. 배열 디스트럭처링 할당" 참고
        const max = 10; // 수열의 최대값
    
        // Symbol.iterator 메서드는 next 메서드를 소유한 이터레이터를 반환해야 하고
        // next 메서드는 이터레이터 리절트 객체를 반환해야 한다.
        return {
          next() {
            [pre, cur] = [cur, pre + cur]; // "36.1. 배열 디스트럭처링 할당" 참고
            // 이터레이터 리절트 객체를 반환한다.
            return { value: cur, done: cur >= max };
          }
        };
      }
    };
    
    // 이터러블인 fibonacci 객체를 순회할 때마다 next 메서드가 호출된다.
    for (const num of fibonacci) {
      console.log(num); // 1 2 3 5 8
    }
    
    // 이터러블은 스프레드 문법의 대상이 될 수 있다.
    const arr = [...fibonacci];
    console.log(arr); // [ 1, 2, 3, 5, 8 ]
    
    // 이터러블은 배열 디스트럭처링 할당의 대상이 될 수 있다.
    const [first, second, ...rest] = fibonacci;
    console.log(first, second, rest); // 1 2 [ 3, 5, 8 ]
    

    反復可能な関数の作成

  • の前に見たmaxで、内部には数列の最大値finboacciFuncがあります.残念なことに、この数列の最大値は固定値であり、外部から渡される値には変更できません.数列の最大値を引数として渡し、最大値を変更できるように小さなかわいい値を返す関数を作成します.
  • // 피보나치 수열을 구현한 사용자 정의 이터러블을 반환하는 함수. 수열의 최대값을 인수로 전달받는다.
    const fibonacciFunc = function (max) {
      let [pre, cur] = [0, 1];
    
      // Symbol.iterator 메서드를 구현한 이터러블을 반환한다.
      return {
        [Symbol.iterator]() {
          return {
            next() {
              [pre, cur] = [cur, pre + cur];
              return { value: cur, done: cur >= max };
            }
          };
        }
      };
    };
    
    // 이터러블을 반환하는 함수에 수열의 최대값을 인수로 전달하면서 호출한다.
    for (const num of fibonacciFunc(10)) {
      console.log(num); // 1 2 3 5 8
    }

    イテレーションオブジェクトのイテレーション関数の作成


    前に説明した
  • 関数を、イテレーションのオブジェクトとして作成され、返される関数に変更します.
  • // 이터러블이면서 이터레이터인 객체를 반환하는 함수
    const fibonacciFunc = function (max) {
      let [pre, cur] = [0, 1];
    
      // Symbol.iterator 메서드와 next 메서드를 소유한 이터러블이면서 이터레이터인 객체를 반환
      return {
        [Symbol.iterator]() { return this; },
        // next 메서드는 이터레이터 리절트 객체를 반환
        next() {
          [pre, cur] = [cur, pre + cur];
          return { value: cur, done: cur >= max };
        }
      };
    };
    
    // iter는 이터러블이면서 이터레이터다.
    let iter = fibonacciFunc(10);
    
    // iter는 이터러블이므로 for...of 문으로 순회할 수 있다.
    for (const num of iter) {
      console.log(num); // 1 2 3 5 8
    }
    
    // iter는 이터러블이면서 이터레이터다
    iter = fibonacciFunc(10);
    
    // iter는 이터레이터이므로 이터레이션 리절트 객체를 반환하는 next 메서드를 소유한다.
    console.log(iter.next()); // { value: 1, done: false }
    console.log(iter.next()); // { value: 2, done: false }
    console.log(iter.next()); // { value: 3, done: false }
    console.log(iter.next()); // { value: 5, done: false }
    console.log(iter.next()); // { value: 8, done: false }
    console.log(iter.next()); // { value: 13, done: true }
    

    無限小と遅延評価

  • を生成する無限のかわいい関数を定義します.これにより,無限数列を簡単に実現できる.
  • // 무한 이터러블을 생성하는 함수
    const fibonacciFunc = function () {
      let [pre, cur] = [0, 1];
    
      return {
        [Symbol.iterator]() { return this; },
        next() {
          [pre, cur] = [cur, pre + cur];
          // 무한을 구현해야 하므로 done 프로퍼티를 생략한다.
          return { value: cur };
        }
      };
    };
    
    // fibonacciFunc 함수는 무한 이터러블을 생성한다.
    for (const num of fibonacciFunc()) {
      if (num > 10000) break;
      console.log(num); // 1 2 3 5 8...4181 6765
    }
    
    // 배열 디스트럭처링 할당을 통해 무한 이터러블에서 3개의 요소만 취득한다.
    const [f1, f2, f3] = fibonacciFunc();
    console.log(f1, f2, f3); // 1 2 3
    
  • 配列や文字列などは、すべてのデータをメモリに保存し、データを提供します.しかし、上記の例のかわいい子は、遅延評価(lazy evaluation)によってデータを生成する.
  • 遅延評価:データが必要になる前にデータを事前に生成しない方法で、データが必要な場合(ex-for...of文または構造分解割当を使用して)データを生成します.

  • 上記のコードを詳しく見ると、for...of文は、ウィジェットを巡回する際に、内部でウィジェットのnextメソッドを呼び出し、このときデータを生成する.nextメソッドが呼び出されるまで、データは生成されません.すなわち、データが必要になる前にデータの生成を遅らせ、データが必要になる瞬間にデータを生成する.

  • この遅延評価の利点は、実行速度が速く、不要なメモリを消費せず、無限量を実現できることです.