ECMAScript 6 학습 노트 - Interator, for...

1. Iterator 개념
스 트 리밍 기 (Iterator) 는 바로 이러한 메커니즘 이다.그것 은 다양한 데이터 구조 에 통 일 된 접근 체 제 를 제공 하 는 인터페이스 이다.모든 데이터 구 조 는 Iterator 인 터 페 이 스 를 배치 하면 옮 겨 다 니 기 작업 을 완성 할 수 있 습 니 다 (즉, 이 데이터 구 조 를 순서대로 처리 하 는 모든 구성원).
Iterator 의 역할 은 세 가지 가 있 습 니 다. 하 나 는 각종 데이터 구 조 를 위해 통일 적 이 고 간편 한 방문 인 터 페 이 스 를 제공 하 는 것 입 니 다.둘째, 데이터 구조의 구성원 들 이 특정한 순서에 따라 배열 할 수 있 도록 하 는 것 이다.셋째, ES6 는 새로운 옮 겨 다 니 는 명령 for... of 순환 을 만 들 었 고 Iterator 인 터 페 이 스 는 주로 for... of 소 비 를 제공 합 니 다.
Iterator 의 옮 겨 다 니 는 과정 은 이 렇 습 니 다.
(1) 현재 데이터 구조의 시작 위 치 를 가리 키 는 포인터 대상 을 만 듭 니 다.즉, 스 트 리밍 대상 은 본질 적 으로 지침 대상 이다.
(2) 포인터 대상 을 처음 호출 하 는 next 방법 은 데이터 구조의 첫 번 째 구성원 에 게 지침 을 가리 킬 수 있다.
(3) 두 번 째 포인터 대상 을 호출 하 는 next 방법 은 데이터 구조의 두 번 째 구성원 을 가리킨다.
(4) 데이터 구조의 끝 위 치 를 가리 킬 때 까지 포인터 대상 의 next 방법 을 계속 호출 합 니 다.
매번 next 방법 을 호출 할 때마다 데이터 구조의 현재 구성원 의 정 보 를 되 돌려 줍 니 다.구체 적 으로 말 하면 value 와 done 두 속성 을 포함 하 는 대상 을 되 돌려 주 는 것 이다.그 중에서 value 속성 은 현재 구성원 의 값 입 니 다. done 속성 은 불 값 입 니 다. 옮 겨 다 니 는 것 이 끝 났 는 지 여 부 를 표시 합 니 다.
다음은 next 방법 을 모 의 하여 값 을 되 돌려 주 는 예 입 니 다.
var it = makeIterator(['a', 'b']);

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

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}

위 코드 는 MakeIterator 함 수 를 정의 합 니 다. 이것 은 스 트 리밍 기 생 성 함수 입 니 다. 스 트 리밍 기 대상 을 되 돌려 주 는 역할 을 합 니 다.배열 [a ',' b '] 에 이 함 수 를 실행 하면 이 배열 의 스 트 리밍 대상 (즉 포인터 대상) it 로 돌아 갑 니 다.
포인터 대상 의 next 방법 은 바늘 을 움 직 이 는 데 쓰 인 다.시작 할 때 포인터 가 배열 의 시작 위 치 를 가리킨다.그리고 next 방법 을 호출 할 때마다 지침 은 배열 의 다음 멤버 를 가리킨다.첫 번 째 호출, a 지향;두 번 째 호출 은 b 를 가리킨다.
next 방법 은 대상 을 되 돌려 현재 데이터 구성원 의 정 보 를 표시 합 니 다.이 대상 은 value 와 done 두 가지 속성 을 가지 고 있 습 니 다. value 속성 은 현재 위치 로 돌아 가 는 구성원 입 니 다. done 속성 은 불 값 입 니 다. 옮 겨 다 니 는 것 이 끝 났 는 지, 즉 next 방법 을 다시 호출 할 필요 가 있 는 지 여부 입 니 다.
한 마디 로 지침 대상 을 호출 하 는 next 방법 은 미리 정 해진 데이터 구 조 를 옮 겨 다 닐 수 있다.
옮 겨 다 니 는 대상 에 게 done: false 와 value: undefined 속성 은 모두 생략 할 수 있 기 때문에 위의 MakeIterator 함 수 는 아래 형식 으로 간략하게 쓸 수 있 습 니 다.
function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++]} :
        {done: true};
    }
  };
}

2. 기본 Iterator 인터페이스 Iterator 인터페이스의 목적 은 모든 데이터 구 조 를 위해 통 일 된 접근 체 제 를 제공 하 는 것 입 니 다. 즉, for... of 순환 (상세 한 내용 은 다음 과 같 습 니 다).for... of 순환 을 사용 하여 특정한 데이터 구 조 를 옮 겨 다 닐 때 이 순환 은 자동 으로 Iterator 인 터 페 이 스 를 찾 습 니 다.
일종 의 데이터 구조 가 Iterator 인 터 페 이 스 를 배치 하면 우 리 는 이러한 데이터 구 조 를 '옮 겨 다 닐 수 있 는' (iterable) 이 라 고 부른다.
ES6 에 따 르 면 기본 Iterator 인 터 페 이 스 는 데이터 구조의 Symbol. iterator 속성 에 배치 되 거나 하나의 데이터 구 조 는 Symbol. iterator 속성 만 있 으 면 '옮 겨 다 닐 수 있 는' (iterable) 이 라 고 볼 수 있다.Symbol. iterator 속성 자체 가 함수 입 니 다. 현재 데이터 구조의 기본 적 인 달력 생 성 함수 입 니 다.이 함 수 를 실행 하면 달력 을 되 돌려 줍 니 다.속성 명 Symbol. iterator 는 표현 식 으로 Symbol 대상 의 iterator 속성 을 되 돌려 줍 니 다. 이것 은 미리 정 의 된 Symbol 형식의 특수 값 이 므 로 괄호 안에 넣 어야 합 니 다.
const obj = {
  [Symbol.iterator] : function () {
    return {
      next: function () {
        return {
          value: 1,
          done: true
        };
      }
    };
  }
};

위의 코드 에서 대상 obj 는 옮 겨 다 닐 수 있 는 (iterable) 입 니 다. Symbol. iterator 속성 이 있 기 때 문 입 니 다.이 속성 을 실행 하면 옮 겨 다 니 는 대상 을 되 돌려 줍 니 다.이 대상 의 근본 적 인 특징 은 next 방법 을 가지 고 있다 는 것 이다.next 방법 을 호출 할 때마다 현재 구성원 을 대표 하 는 정보 대상 을 되 돌려 줍 니 다. value 와 done 두 가지 속성 이 있 습 니 다.
ES6 의 일부 데이터 구 조 는 원래 Iterator 인터페이스 (예 를 들 어 배열) 를 갖 추고 있 습 니 다. 즉, 어떠한 처리 도 하지 않 아 도 for.. of 순환 으로 옮 겨 다 닐 수 있 습 니 다.이 유 는 이러한 데이터 구 조 는 원래 Symbol. iterator 속성 을 배 치 했 고 다른 데이터 구 조 는 (예 를 들 어 대상) 이 없 기 때문이다.Symbol. iterator 속성 을 배치 한 데이터 구 조 를 스 트 리밍 인터페이스 라 고 합 니 다.이 인 터 페 이 스 를 호출 하면 옮 겨 다 니 는 대상 을 되 돌려 줍 니 다.
원생 Iterator 인 터 페 이 스 를 갖 춘 데이터 구 조 는 다음 과 같다.
  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 함수 의 arguments 대상
  • 다음 예 는 배열 의 Symbol. iterator 속성 입 니 다.
    let arr = ['a', 'b', 'c'];
    let iter = arr[Symbol.iterator]();
    
    iter.next() // { value: 'a', done: false }
    iter.next() // { value: 'b', done: false }
    iter.next() // { value: 'c', done: false }
    iter.next() // { value: undefined, done: true }

    원생 배치 Iterator 인터페이스의 데이터 구조 에 대해 서 는 자체 적 으로 스 트 리밍 기 생 성 함 수 를 쓰 지 않 아 도 됩 니 다. for.. of 순환 은 자동 으로 스 트 리밍 됩 니 다.그 밖 에 다른 데이터 구조 (주로 대상) 의 Iterator 인 터 페 이 스 는 모두 자신 이 Symbol. iterator 속성 에 배치 해 야 for... of 순환 으로 옮 겨 다 닐 수 있 습 니 다.
    대상 이 for... of 순환 호출 이 가능 한 Iterator 인 터 페 이 스 를 갖 추 려 면 Symbol. iterator 의 속성 에 스 트 리밍 기 생 성 방법 을 배치 해 야 합 니 다.
    class RangeIterator {
      constructor(start, stop) {
        this.value = start;
        this.stop = stop;
      }
    
      [Symbol.iterator]() { return this; }
    
      next() {
        var value = this.value;
        if (value < this.stop) {
          this.value++;
          return {done: false, value: value};
        }
        return {done: true, value: undefined};
      }
    }
    
    function range(start, stop) {
      return new RangeIterator(start, stop);
    }
    
    for (var value of range(0, 3)) {
      console.log(value); // 0, 1, 2
    }

    유사 한 배열 의 대상 (수치 키 이름과 length 속성 이 존재 함) 에 대해 Iterator 인 터 페 이 스 를 배치 하 는 간단 한 방법 은 Symbol. iterator 방법 으로 배열 의 Iterator 인 터 페 이 스 를 직접 참조 하 는 것 입 니 다.
    NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
    //   
    NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
    
    [...document.querySelectorAll('div')] //      

    Symbol. iterator 방법 에 대응 하 는 스 트 리밍 생 성 함수 (즉 스 트 리밍 대상 을 되 돌려 줍 니 다) 가 아니라면 엔진 이 잘못 되 었 습 니 다.
    var obj = {};
    
    obj[Symbol.iterator] = () => 1;
    
    [...obj] // TypeError: [] is not a function

    3. Iterator 인 터 페 이 스 를 호출 하 는 장소
    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']

    3. yield * 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. 다른 장소
    배열 의 스 트 리밍 은 스 트 리밍 인 터 페 이 스 를 호출 하기 때문에 배열 을 매개 변수 로 받 아들 이 는 모든 경우 스 트 리밍 인 터 페 이 스 를 호출 합 니 다.다음은 몇 가지 예 이다.
  • for…of
  • Array.from()
  • Map (), Set (), WeakMap (), WeakSet () (예 를 들 어 new Map (['a', 1], ['b', 2])
  • Promise.all()

  • 4. 문자열 의 Iterator 인터페이스 문자열 은 배열 과 유사 한 대상 이 고 원생 Iterator 인터페이스 도 있 습 니 다.
    var someString = "hi";
    typeof someString[Symbol.iterator]
    // "function"
    
    var iterator = someString[Symbol.iterator]();
    
    iterator.next()  // { value: "h", done: false }
    iterator.next()  // { value: "i", done: false }
    iterator.next()  // { value: undefined, done: true }

    원생 의 Symbol. iterator 방법 을 덮어 쓰 고 옮 겨 다 니 는 행 위 를 수정 하 는 목적 을 달성 할 수 있 습 니 다.
    var str = new String("hi");
    
    [...str] // ["h", "i"]
    
    str[Symbol.iterator] = function() {
      return {
        next: function() {
          if (this._first) {
            this._first = false;
            return { value: "bye", done: false };
          } else {
            return { done: true };
          }
        },
        _first: true
      };
    };
    
    [...str] // ["bye"]
    str // "hi"

    5. Iterator 인터페이스 와 Generator 함수
    Symbol. iterator 방법의 가장 간단 한 실현 은 다음 장 에서 소개 할 Generator 함 수 를 사용 하 는 것 입 니 다.
    let myIterable = {
      [Symbol.iterator]: function* () {
        yield 1;
        yield 2;
        yield 3;
      }
    }
    [...myIterable] // [1, 2, 3]
    
    //            
    
    let obj = {
      * [Symbol.iterator]() {
        yield 'hello';
        yield 'world';
      }
    };
    
    for (let x of obj) {
      console.log(x);
    }
    // "hello"
    // "world"

    6. 옮 겨 다 니 는 대상 의 return (), throw ()
    스 트 리밍 대상 은 next 방법 외 에 return 방법 과 throw 방법 도 있 습 니 다.옮 겨 다 니 는 대상 생 성 함 수 를 직접 쓰 면 next 방법 은 반드시 배치 해 야 합 니 다. return 방법 과 throw 방법 은 배치 여 부 를 선택 할 수 있 습 니 다.
    return 방법의 사용 장 소 는 for... of 순환 이 미리 종료 되면 return 방법 을 사용 합 니 다.대상 이 옮 겨 다 니 기 전에 자원 을 정리 하거나 방출 해 야 한다 면 return 방법 을 배치 할 수 있 습 니 다.
    function readLinesSync(file) {
      return {
        [Symbol.iterator]() {
          return {
            next() {
              return { done: false };
            },
            return() {
              file.close();
              return { done: true };
            }
          };
        },
      };
    }

    위의 코드 에서 함수 readLinesSync 는 파일 대상 을 매개 변수 로 받 아들 여 스 트 리밍 대상 을 되 돌려 줍 니 다. 그 중에서 next 방법 을 제외 하고 return 방법 도 배 치 했 습 니 다.아래 의 세 가지 상황 은 모두 return 방법 을 실행 합 니 다.
    //    
    for (let line of readLinesSync(fileName)) {
      console.log(line);
      break;
    }
    
    //    
    for (let line of readLinesSync(fileName)) {
      console.log(line);
      continue;
    }
    
    //    
    for (let line of readLinesSync(fileName)) {
      console.log(line);
      throw new Error();
    }

    위의 코드 에서 상황 이 파일 의 첫 줄 을 출력 하면 return 방법 을 실행 하여 이 파일 을 닫 습 니 다.상황 2. 모든 줄 을 출력 한 후 return 방법 을 실행 하고 이 파일 을 닫 습 니 다.상황 3 은 return 방법 으로 파일 을 닫 은 후에 오 류 를 던 집 니 다.return 방법 은 대상 을 되 돌려 야 합 니 다. 이것 은 Generator 규격 에 의 해 결 정 된 것 입 니 다.
    7. for... of 순환
    하나의 데이터 구 조 는 Symbol. iterator 속성 을 배치 하면 iterator 인터페이스 가 있 는 것 으로 간주 되 며, for... of 순환 으로 구성원 을 옮 겨 다 닐 수 있 습 니 다.즉, for... of 순환 내부 에서 호출 된 것 은 데이터 구조의 Symbol. iterator 방법 입 니 다.
    for... of 순환 에서 사용 할 수 있 는 범 위 는 배열, Set 와 Map 구조, 일부 유사 한 배열 의 대상 (예 를 들 어 arguments 대상, DOM NodeList 대상), 뒤의 Generator 대상, 그리고 문자열 을 포함한다.
    1. 배열 배열 은 원래 iterator 인터페이스 (즉, Symbol. iterator 속성 이 기본적으로 배치 되 어 있 음) 를 갖 추고 있 습 니 다. for.. of 순환 은 본질 적 으로 이 인터페이스 에서 발생 하 는 스 트 리밍 기 를 호출 하 는 것 입 니 다. 아래 코드 로 증명 할 수 있 습 니 다.
    const arr = ['red', 'green', 'blue'];
    
    for(let v of arr) {
      console.log(v); // red green blue
    }
    
    const obj = {};
    obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);
    
    for(let v of obj) {
      console.log(v); // red green blue
    }
    //   obj     arr Symbol.iterator  ,  obj for...of  ,    arr       。

    for... of 순환 은 배열 의 인 스 턴 스 를 대체 할 수 있 는 foreach 방법 입 니 다.
    const arr = ['red', 'green', 'blue'];
    
    arr.forEach(function (element, index) {
      console.log(element); // red green blue
      console.log(index);   // 0 1 2
    });

    JavaScript 기 존의 for... in 순환 은 대상 의 키 만 얻 을 수 있 고 키 값 을 직접 가 져 올 수 없습니다.ES6 는 for... of 순환 을 제공 합 니 다. 키 값 을 가 져 올 수 있 습 니 다.
    var arr = ['a', 'b', 'c', 'd'];
    
    for (let a in arr) {
      console.log(a); // 0 1 2 3
    }
    
    for (let a of arr) {
      console.log(a); // a b c d
    }

    for... of 순환 호출 스 트 리밍 인터페이스, 배열 의 스 트 리밍 인 터 페 이 스 는 디지털 색인 이 있 는 속성 만 되 돌려 줍 니 다.이 점 은 for... in 순환 과 도 다르다.
    let arr = [3, 5, 7];
    arr.foo = 'hello';
    
    for (let i in arr) {
      console.log(i); // "0", "1", "2", "foo"
    }
    
    for (let i of arr) {
      console.log(i); //  "3", "5", "7"
    }
    //for...of        arr foo  。

    2. Set 와 Map 구조
    Set 와 Map 구조 도 원생 Iterator 인터페이스 가 있어 for... of 순환 을 직접 사용 할 수 있 습 니 다.
    var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
    for (var e of engines) {
      console.log(e);
    }
    // Gecko
    // Trident
    // Webkit
    
    var es6 = new Map();
    es6.set("edition", 6);
    es6.set("committee", "TC39");
    es6.set("standard", "ECMA-262");
    for (var [name, value] of es6) {
      console.log(name + ": " + value);
    }
    // edition: 6
    // committee: TC39
    // standard: ECMA-262

    위의 코드 는 Set 구조 와 Map 구 조 를 어떻게 옮 겨 다 니 는 지 보 여 주 었 다.주의해 야 할 점 은 두 가지 가 있다. 우선, 옮 겨 다 니 는 순 서 는 각 구성원 이 데이터 구조 에 추 가 된 순서 다.그 다음 에 Set 구 조 는 시간 이 지나 면 하나의 값 을 되 돌려 주 고 Map 구 조 는 시간 이 지나 면 하나의 배열 을 되 돌려 줍 니 다. 이 배열 의 두 구성원 은 현재 Map 구성원 의 키 이름과 키 입 니 다.
    let map = new Map().set('a', 1).set('b', 2);
    for (let pair of map) {
      console.log(pair);
    }
    // ['a', 1]
    // ['b', 2]
    
    for (let [key, value] of map) {
      console.log(key + ' : ' + value);
    }
    // a : 1
    // b : 2

    참조: ECMAScript 6 입문

    좋은 웹페이지 즐겨찾기