[ES6] Ruan Yifeng ES6 학습 반복자와 for...of 루프

1. 반복자

1. 개념

Iterator는 그러한 메커니즘입니다. 다양한 데이터 구조에 대한 통합 액세스 메커니즘을 제공하는 인터페이스입니다. 모든 데이터 구조가 Iterator 인터페이스를 배포하는 한 순회 작업을 완료할 수 있습니다(즉, 데이터 구조의 모든 멤버를 차례로 처리).

Iterator에는 세 가지 기능이 있습니다.

  • 하나는 다양한 데이터 구조에 대한 통합되고 편리한 액세스 인터페이스를 제공하는 것입니다.
  • 두 번째는 데이터 구조의 구성원을 특정 순서로 정렬할 수 있도록 하는 것입니다.
  • 세 번째는 ES6가 for…of 루프를 위한 새로운 순회 명령을 만들었고 Iterator 인터페이스는 주로 for…of 소비에 사용된다는 것입니다.

2. 작동 원리

  1. 현재 데이터 구조의 시작을 가리키는 포인터 개체를 만듭니다. 즉, traverser 객체는 본질적으로 포인터 객체입니다.

  2. next포인터 개체의 메서드가 처음 호출될 때 포인터는 데이터 구조의 첫 번째 멤버를 가리킬 수 있습니다.

  3. 포인터 개체의 메서드가 두 번째로 호출되면 next포인터는 데이터 구조의 두 번째 멤버를 가리킵니다.

  4. next데이터 구조의 끝을 가리킬 때까지 포인터 개체에서 메서드를 계속 호출합니다 .

메소드가 호출될 때마다 개의 속성을 포함하는 객체가 next반환됩니다 . 그 중 속성은 현재 멤버의 값이고 속성은 순회가 끝났음을 나타내는 부울 값이다.valuedonevaluedone

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};
    }
  };
}

3. 기본 Iterator 인터페이스

데이터 구조가 Iterator 인터페이스를 배포하는 한 이 데이터 구조를 "순회 가능"(반복 가능)이라고 합니다.

ES6는 기본 Iterator 인터페이스가 데이터 구조의 속성에 배포된다고 규정합니다 Symbol.iterator. 즉, 데이터 구조에 Symbol.iterator속성이 있는 한 "반복 가능한" 것으로 간주할 수 있습니다.

Symbol.iterator속성 자체는 현재 데이터 구조의 기본 순회자 생성 함수인 함수입니다. 이 함수를 실행하면 반복자가 반환됩니다.

const obj = {
    
    
  [Symbol.iterator] : function () {
    
    
    return {
    
    
      next: function () {
    
    
        return {
    
    
          value: 1,
          done: true
        };
      }
    };
  }
};

ES6는 새로운 순회 명령 for…of루프를 생성하며 Iterator 인터페이스는 주로 for…of사용 됩니다.

반복자 인터페이스가 있는 기본 데이터( for...of순회 가능)

  • 정렬
  • 지도
  • 세트
  • TypedArray
  • 함수의 인수 객체
  • NodeList 개체
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 }

4. Iterator 인터페이스 호출 시

경우에 따라 기본적으로 Iterator 인터페이스(즉, 메서드)가 호출되며, Symbol.iterator아래에서 설명하는 for...of루프 외에도 여러 가지 경우가 있습니다.

(1) 디스트럭처링 할당

Symbol.iterator 메서드는 배열과 Set 구조를 분해하고 할당할 때 기본적으로 호출됩니다.

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*순회 가능한 구조 다음에 구조의 순회자 인터페이스를 호출합니다.

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) 기타 경우

배열의 순회는 순회 인터페이스를 호출하므로 배열을 매개변수로 받아들이는 모든 경우는 실제로 순회 인터페이스를 호출합니다. 다음은 몇 가지 예입니다.

  • ...의
  • 배열.from()
  • Map(), Set(), WeakMap(), WeakSet()(예: new Map([['a',1],['b',2]]))
  • 약속.모두()
  • 약속.경주()

2. for...of 루프

1. 어레이

const arr = ['red', 'green', 'blue'];

for(let v of arr) {
    
    
  console.log(v); // red green blue
}

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. 세트 및 맵 구조

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

3. 배열과 같은 객체

배열과 같은 객체에는 여러 클래스가 포함됩니다. 다음은 문자열, DOM NodeList 객체 및 인수 객체에 대한 for...of 루프의 예입니다.

// 字符串
let str = "hello";

for (let s of str) {
    
    
  console.log(s); // h e l l o
}

// DOM NodeList对象
let paras = document.querySelectorAll("p");

for (let p of paras) {
    
    
  p.classList.add("test");
}

// arguments对象
function printArgs() {
    
    
  for (let x of arguments) {
    
    
    console.log(x);
  }
}
printArgs('a', 'b');
// 'a'
// 'b'

모든 배열과 같은 객체에 Iterator 인터페이스가 있는 것은 아닙니다. 간단한 해결책은 Array.from 메서드를 사용하여 배열로 변환하는 것입니다.

let arrayLike = {
    
     length: 2, 0: 'a', 1: 'b' };

// 报错
for (let x of arrayLike) {
    
    
  console.log(x);
}

// 正确
for (let x of Array.from(arrayLike)) {
    
    
  console.log(x);
}

4. 개체

일반 객체의 경우 for...of구조체를 직접 사용할 수 없으며 오류가 보고되고 Iterator 인터페이스를 배포해야 사용할 수 있습니다. 그러나 이 경우에도 for...in루프를 사용하여 키 이름을 탐색할 수 있습니다.

let es6 = {
    
    
  edition: 6,
  committee: "TC39",
  standard: "ECMA-262"
};

for (let e in es6) {
    
    
  console.log(e);
}
// edition
// committee
// standard

for (let e of es6) {
    
    
  console.log(e);
}
// TypeError: es6[Symbol.iterator] is not a function

위의 코드는 일반 객체의 경우 for...in루프가 키 이름을 트래버스할 수 있고 for...of루프가 오류를 보고함을 나타냅니다.

한 가지 해결책은 메서드를 사용하여 Object.keys개체의 키 이름 배열을 생성한 다음 배열을 트래버스하는 것입니다.

for (var key of Object.keys(someObject)) {
    
    
  console.log(key + ': ' + someObject[key]);
}

또 다른 방법은 Generator 함수를 사용하여 개체를 다시 압축하는 것입니다.

const obj = {
    
     a: 1, b: 2, c: 3 }

function* entries(obj) {
    
    
  for (let key of Object.keys(obj)) {
    
    
    yield [key, obj[key]];
  }
}

for (let [key, value] of entries(obj)) {
    
    
  console.log(key, '->', value);
}
// a -> 1
// b -> 2
// c -> 3

3. 다른 순회 구문과의 비교

배열을 예로 들면 JavaScript는 다양한 순회 구문을 제공합니다. 가장 원시적인 작성 방법은 for 루프입니다.

for (var index = 0; index < myArray.length; index++) {
    
    
  console.log(myArray[index]);
}

이러한 작성 방식은 번거롭기 때문에 배열은 내장된 forEach메서드를 제공합니다.

myArray.forEach(function (value) {
    
    
  console.log(value);
});

forEach이 작성 방법의 문제점은 루프 에서 벗어날 방법이 없고 break명령도 return명령도 작동하지 않는다는 것입니다.

for...in루프는 배열의 키를 반복할 수 있습니다.

for (var index in myArray) {
    
    
  console.log(myArray[index]);
}

for...in루프에는 몇 가지 단점이 있습니다.

  1. 배열의 키는 숫자이지만 for...in루프는키 이름은 "0", "1", "2" 등입니다.
  2. for...in루프는 숫자 키 이름을 반복할 뿐만 아니라 프로토타입 체인의 키를 포함하여 수동으로 추가된 다른 키도 반복합니다.
  3. 어떤 경우에는 for...in 루프가 임의의 순서로 키를 반복합니다.

요컨대, for...in주기는 주로 다음을 위한 것입니다.트래버스 개체설계상 배열 순회에는 적합하지 않습니다.

for...of위의 여러 접근 방식과 비교할 때 루핑에는 몇 가지 중요한 이점이 있습니다.

for (let value of myArray) {
    
    
  console.log(value);
}
  1. 동일한 간결한 구문을 사용 for...in하지만 for...in이러한 단점은 없습니다.
  2. forEach메소드와 달리 break、continue和return.
  3. 모든 데이터 구조를 순회하기 위한 통합 작업 인터페이스를 제공합니다.

다음은 문을 사용하여 루프 break에서 벗어나는 예입니다 .for...of

for (var n of fibonacci) {
    
    
  if (n > 1000)
    break;
  console.log(n);
}

위의 예는 피보나치 수열이 1000보다 작거나 같은 항목을 출력합니다. 현재 항목이 1000보다 크면 문을 사용하여 루프를 break중단합니다 .for...of

Guess you like

Origin blog.csdn.net/Bon_nenul/article/details/128236461
Recommended