Search

11. 반복자 및 제네레이터

목차
*JavaScript 1.7 에 도입
집합체의 각 항목을 처리하는 것은 매우 일반적인 작업입니다. JavaScript는 집합체에 반복하는 몇 가지 방법을 제공하며, 간단한 for 및 for each 루프에서 map () , filter () 와 배열 내포 까지 있습니다. JavaScript 1.7에 도입 된 반복기 및 제네레이터는 언어의 핵심 부분에 직접 반복 아이디어를 도입하고, for ... in 및 for each 루프 동작을 사용자 지정하는 방법을 제공합니다.

반복자

반복자는 일련의 처리에서 현재 위치를 계속 추적하는 동안 집합체 항목 하나씩에 어떻게 접근 하는지를 알고있는 객체입니다. JavaScript에서 반복자는 일련의 과정의 다음 항목을 반환 next () 메서드를 제공하는 개체입니다. 이 방법은 일련의 처리가 종료 한 경우, 임의로 StopIteration 예외를 발생시킬 수 있습니다.
반복자 객체 생성되면 next () 를 반복 호출하여 명시 적으로 또는 JavaScript의 for ... in 및 for each 생성자에서 암시 적으로 사용 될 수 있습니다.
개체와 배열을위한 간단한 반복자는 Iterator () 함수를 사용하여 만들 수 있습니다 :
var lang = {name : 'JavaScript' , birthYear : 1995}; var it = Iterator (lang);
JavaScript
복사
초기화 후에는 개체의 키와 값 쌍에 차례로 액세스하기 위해 next () 메서드를 호출 할 수 있습니다 :
var pair = it.next (); // 쌍은 [ "name", "JavaScript"] pair = it.next (); // 쌍은 [ "birthYear", 1995] pair = it.next (); // StopIteration 예외가 발생
JavaScript
복사
next () 메서드를 직접 호출하는 대신 for ... in 루프를 사용할 수 있습니다. 루프는 StopIteration 예외가 발생했을 때 자동으로 종료합니다.
var it = Iterator (lang); for ( var pair in it) print (pair); // 각각의 key, value] 쌍을 차례로 표시
JavaScript
복사
개체의 키에 대해서만 반복하고 싶다면, Iterator () 함수의 제 2 인수에 true 를 전달합니다 :
var it = Iterator (lang, true ); for ( var Key in it) print (key); // 각 key를 차례로 표시
JavaScript
복사
개체의 내용에 액세스 Iterator () 를 사용의 장점은 Object.prototype 에 추가 한 고유 한 속성이 일련의 처리에 포함되지 않는 것입니다.
Iterator () 는 배열도 사용할 수 있습니다 :
var langs = 'JavaScript' , 'Python' , 'C + +' ]; var it = Iterator (langs); for ( var pair in it) print (pair); // 각각의 index, language] 쌍을 차례로 표시
JavaScript
복사
개체와 마찬가지로, 제 2 인수에 true 를 전달 배열의 인덱스에 반복 할 수 있습니다 :
var langs = 'JavaScript' , 'Python' , 'C + +' ]; var it = Iterator (langs, true ); for ( var I in it) print (i); // 0, 1, 2 출력
JavaScript
복사
for 루프에서 let 키워드를 이용하여 블록 범위에 포함 된 변수를 인덱스 값으로 지정할 수, 인덱스와 값을 분할하여 할당 할 수 있습니다 :
var langs = 'JavaScript' , 'Python' , 'C + +' ]; var it = Iterator (langs); for (let [i, lang] in it) print (i + ':' + lang); // "0 : JavaScript '등을 출력
JavaScript
복사

자신의 반복자의 정의

항목의 집합체를 나타내는 일부 개체는 특정 방법으로 반복하는 것이 좋습니다.
범위의 객체의 반복은 그 범위의 숫자를 차례로 반환해야합니다.
트리의 잎은 깊이 우선 또는 너비 우선 탐색 법에 따를 수 있습니다.
데이터베이스 쿼리의 출력을 나타내는 개체의 반복은 출력 세트 전체가 하나의 배열에 포함되지 않은 경우에도 행을 차례로 반환해야합니다.
무한 수열 (피보나치 수열 등)의 반복은 무한 길이의 데이터 구조를 만들 필요없이 결과를 차례로 상환한다.JavaScript에서는 자체 반복 논리의 코드를 작성하고 그것을 개체와 연결할 수 있습니다.
하한과 상한 값을 저장하는 간단한 Range 개체를 만듭니다.
Function Range (low, high) { this . low = low; this . high = high; }
JavaScript
복사
여기서 위의 범위에 포함 된 정수 시퀀스를 반환 자체 반복자를 만듭니다. 반복자 인터페이스는 일련의 데이터에서 항목을 반환하거나 StopIteration 예외를 던지는, next () 메소드를 제공해야합니다.
Function RangeIterator (range) { this . range = range; this . current = this . range.low; } RangeIterator.prototype.next = function () { if ( this . current> this . range.high) throw StopIteration; else return this . current + +; };
JavaScript
복사
RangeIterator 은 range의 인스턴스와 함께 인스턴스화 된 일련의 데이터에서 어디까지 진행되었는지를 추적하기위한 current 속성을 유지합니다.
그리고 RangeIterator 를 Range 개체에 연결하는 데, Range 에 특별한 방법이다 __iterator__ 을 추가해야합니다. 이 메서드는 Range 의 인스턴스에서 반복 할 때 호출, 반복의 논리를 구현하는 RangeIterator 의 인스턴스를 돌려줍니다.
Range.prototype.__iterator__ = function () { return New RangeIterator ( this ); };
JavaScript
복사
자신의 반복 후크하면 range 인스턴스의 반복을 다음과 같이 할 수 있습니다 :
var range = New Range (3, 5); for ( var I in range) print (i); // 차례로 3, 4, 5를 출력
JavaScript
복사

제네레이터(생성기) : 반복자를 구축하는 더 나은 방법

자신의 반복은 유용한 수단이지만, 내부의 상태를 명시 적으로 관리 할 필요가 있기 때문에, 반복자의 작성은 신중 프로그래밍하는 것이 요구됩니다. 제네레이터는 강력한 대안을 제공합니다. 이것은 자신의 상태를 관리 할 수있는 함수 하나를 작성하여, 반복 알고리즘의 정의를 가능하게합니다.
제너레이터는 반복자의 생성 원으로 일하는 특별한 종류의 함수입니다. 하나 이상의 yield 식을 포함하는 경우, 함수 발생기입니다.
주의: HTML에서 yield 키워드는 < script type="application/javascript;version=1.7" > (또는 상위 버전)의 블록에 포함 된 코드 블록에서만 사용할 수 있습니다. XUL 의 script 태그는이 기능의 사용시 특별한 블록을 필요로하지 않습니다. 제네레이터 함수가 함수 본문에서 호출해도 바로 실행되지 않습니다. 대신 발생기 반복자 오브젝트를 돌려줍니다. 각 발생기 반복자의 next () 메서드를 호출하면, 함수의 본체를 다음 yield 식까지 실행하고 그 결과를 돌려줍니다. 함수의 종료 또는 return 문에 도달하면 StopIteration 예외가 발생합니다.
이 동작은 다음 예에서 잘 표현되어 있습니다 :
Function simpleGenerator () { yield "first" ; yield "second" ; yield "third" ; for ( var I = 0; i <3; i + +) yield i; } var g = simpleGenerator (); print (g.next ()); // "first"를 출력 print (g.next ()); // "second"을 출력 print (g.next ()); // "third"을 출력 print (g.next ()); // 출력 : 0print (g.next ()); // 1을 출력 print (g.next ()); // 2를 출력 print (g.next ()); // StopIteration가 발생
JavaScript
복사
생성기 함수는 클래스의 __iterator__ 메서드로 직접 사용할 수 자체 반복자를 만드는 데 필요한 코드의 양을 획기적으로 줄일 수 있습니다. 다음은 앞의 Range 를 생성기를 사용하여 다시 작성합니다 :
Function Range (low, high) { this . low = low; this . high = high; } Range.prototype.__iterator__ = function () { for ( var I = this . low; i <= this . high; i + +) yield i; }; var range = New Range (3, 5); for ( var I in range) print (i); // 차례로 3, 4, 5를 출력
JavaScript
복사
모든 제네레이터가 종료하는 것은 아닙니다. 무한 시퀀스를 나타내는 생성기를 만들 수 있습니다. 다음 생성기는 피보나치 수열을 구현하고, 각 요소는 자신의 전 요소 두 값을 합계 한 것입니다 :
Function fibonacci () { var Fn1 = 1; var Fn2 = 1; while (1) { var Current = fn2; fn2 = fn1; fn1 = fn1 + current; yield current; } } var sequence = fibonacci (); print (sequence.next ()); // 1 print (sequence.next ()); // 1 print (sequence.next ()); // 2 print (sequence.next ()); // 3 print (sequence.next ()); // 5 print (sequence.next ()); // 8 print (sequence.next ()); // 13
JavaScript
복사
생성기 함수는 인수를 취할 수, 그것은 시작에 함수가 호출 될 때 연결됩니다. 생성기는 return 문 ( StopIteration 예외를 발생시켜) 종료 할 수 있습니다. 다음 fibonacci () 는 선택적 limit 인수를 가진 파생 형으로, limit가 전달 된 경우에 종료 할 것입니다.
Function fibonacci (limit) { var Fn1 = 1; var Fn2 = 1; while (1) { var Current = fn2; fn2 = fn1; fn1 = fn1 + current; if (limit && current> limit) return ; yield current; } }
JavaScript
복사

고급 제네레이터

제네레이터 창출 값을 요청에 따라 계산하고, 많은 계산이 필요한 일련의 데이터를 효율적으로 표현하고 앞과 무한으로 이어지는 데이터를 표현 할 수 있도록합니다.
발생기 반복자 객체는 next () 메소드 외에도 생성기의 내부 상태를 변경하는 데 사용할 수있는 send () 메서드를 가지고 있습니다. send () 에 전달 된 값은 생성기가 마지막에 멈춰 섰다 yield 의 결과로 간주됩니다. 특정 값을 전달 send () 를 사용하기 전에 적어도 한 번 next () 를 호출하여 제네레이터를 시작해야합니다.
다음 fibonacci 생성기는 수열을 다시 시작하기 위해 send () 을 사용하고 있습니다 :
Function fibonacci () { var Fn1 = 1; var Fn2 = 1; while (1) { var Current = fn2; fn2 = fn1; fn1 = fn1 + current; var reset = yield current; if (reset) { fn1 = 1; fn2 = 1; } } } var sequence = fibonacci (); print (sequence.next ()); // 1 print (sequence.next ()); // 1 print (sequence.next ()); // 2 print (sequence.next ()); // 3 print (sequence.next ()); // 5 print (sequence.next ()); // 8 print (sequence.next ()); // 13 print (sequence.send ( true )); // 1 print (sequence.next ()); // 1 print (sequence.next ()); // 2 print (sequence.next ()); // 3
JavaScript
복사
주의 : 흥미로운 점은 send (undefined) 의 호출은 next () 와 동일하다 수 있습니다. 그러나 send () 를 호출하면 undefined 이외의 값으로 새로운 제네레이터를 시작하면 TypeError 예외가 발생할 것입니다.제네레이터의 throw () 메서드를 호출하여 발생하는 예외를 전달하여 생성기에 예외를 발생시킬 수 있습니다. 이 예외는 제네레이터가 현재 머물고있는 상황에서 현재 머물고있는 yield 가 throw value 글에 바뀌었던 것처럼 던져 있습니다.
발생한 예외를 처리하는 동안 yield에 우연히 않으면 예외가 throw () 의 호출을 통해 전파 이후 next () 를 호출 StopIteration 가 발생할 수 있습니다.
생성기는 자신을 닫시키는 close () 메소드를 가지고 있습니다. 생성기를 닫을의 효과는 다음과 같습니다 :
실행중인 생성기 함수 활성 모든 finally 절이 실행됩니다finally 절 StopIteration 이외의 예외가 발생하면 예외는 close () 메서드 호출에 전달합니다.생성기가 종료됩니다.

제네레이터 식

*JavaScript 1.8 에 도입
배열 내포 중요한 단점은 메모리에 새로운 배열 전체를 구축하고 있다는 것이다. 배열 내포에 입력 자체가 작은 배열 일 때의 오버 헤드는 작 습니다만, 입력이 큰 배열이나 처리가 많은 (혹은 정말 무한) 생성기 인 경우 배열 만들기 문제가 될 수 있습니다 .
생성기는 아이템을 필요할 때 요청에 따라 산출하는 일련의 데이터 계산을 줄일 수 있습니다. 제네레이터 식 구문으로 배열 내포와 거의 동일합니다. 이쪽은 중괄호 대신 괄호를 사용하여 (또한, for each ... in 대신 for ... in 을 사용), 배열을 구축하는 대신, 즉시 실행되지 제네레이터를 작성 있습니다. 이들은 생성기를 간단하게 한 구문과 생각할 수 있습니다.
정수의 대규모 수열을 반복하는 반복자 it 가정합니다. 수열의 값을 두 배로 반복하는 새로운 반복자를 작성하려고합니다. 배열 내포에서는 2 배의 값을 포함하는 충분한 배열을 메모리에 만듭니다.
var doubles = [i * 2 for (I in it);
JavaScript
복사
한편 생성기 식은 필요할 때 요청에 따라 2 배의 값을 생성하는 반복자를 만듭니다 :
var it2 = (i * 2 for (I in it)); print (it2.next ()); // it의 첫 번째 값을 두 배로 print (it2.next ()); // it의 두 번째 값을 두 배로
JavaScript
복사
생성기 표현식이 함수의 인수로 사용되는 경우 함수 호출에 사용되는 괄호는 제네레이터 식 외부의 괄호를 생략 할 수 있습니다 :
var result = doSomething (i * 2 for (I in it));
JavaScript
복사

저작권 공지

이 문서의 모든 저작권은 Mozilla.org에 있습니다. 이 문서는 "모질라 기여자"들에 의해 작성 되었습니다. 원문 보기 저희가 한글로 번역한 2차적저작물에 대한 저작권 역시 Mozilla.org에 있습니다.