generator(一)-generator기초와iterator의 관계를 상세히 설명하다

7696 단어

generator 기초


generator의 구조와 함수의 구성은 같지만 성명 형식이 다르다. 예를 들어 function *foo(){} 또는 function*foo(){} (공칸 없음) 이다.
먼저 generator의 간단한 예를 봅시다.
let a=1
function *foo(){
    a++
    yield
    console.log(`a:${a}`)
}

function bar(){
    a++
}

//  it generator
const it=foo()
//  foo()
it.next() // a->2
bar() // a->3
it.next() //  : a:3

기억해!첫 번째next()는 초기화 시작generator입니다.

입력 출력


1. 교체 메시지 전달

function *foo(x){
    const y=x*(yield)
    return y
}

const it=foo(2)
//  *foo(), 
it.next()  // ->{value: undefined, done: false}
//  3 yield , const y=2*3
const res=it.next(3) // ->{value: 6, done: true}
res.value // 6

첫 번째next()는 항상 시작해야 하기 때문에generatornext()는 일일이 일치하지 않습니까?

2. 양방향 메시지 전달


우리는 교체기의 측면에서 yieldnext()의 관계를 본다. yield는 하나의 표현식으로서 메시지 응답yield ...을 호출할 수 있고, next(..)도 일시 정지된 next(..) 표현식에 값을 보낼 수 있다. 메시지는 양방향으로 전달된다.
위의 예를 고치십시오.
function *foo(x){
    const y=x*(yield 'hello')
    return y
}

const it=foo(2)
it.next() //-> {value: "hello", done: false}
it.next(3) // ->{value: 6, done: true}

generator 시작 부분에서, 우리가 첫 번째 yield 를 호출할 때, 아직 멈추지 않은 next() 은 이 값을 받아들인다.첫 번째yield의 호출은 기본적으로 하나의 문제를 제기한다. generatornext()가 나에게 줄 다음 값이 무엇인지, 첫 번째*foo가 이 문제를 대답한다.

다중 교체기


일반적인 함수에서 두 함수를 교체하여 실행하는 것은 불가능하다!A 함수가 먼저 실행되거나, B 함수가 먼저 실행됩니다.
그러나generator를 사용하여 교체하여 집행하는 것은 분명히 능숙하다!
let a=1
let b=2
function *foo(){
    a++
    yield
    b=b*a
    a=(yield b)+3
}

function *bar(){
    b--
    yield
    a=(yield 8)+b
    b=a*(yield 2)
}

상기 두 개generator는 공유된 같은 변수에서 교체하여 실행하고 교체기의 제어에 따라 앞의 프로그램은 여러 가지 다른 결과를 낼 수 있다.
우리는 교체기를 제어하기 위해 보조 함수를 만듭니다.
function step(gen){
    let it=gen()
    let last;
    return function(){
        //  yield , 
        last=it.next(last).value
    }
}

교대 운행 yield 'hello'*foo() 을 시험해 보겠습니다.
const s1=step(foo)
const s2=step(bar)

s2() // b-- b=1
s2() // yield 8
s1() // a++ a=2
s2() // a=8+b a=9
     // yield 2
s1() // b=b*a b=9
     // yield b
s1() // a=b+3 12
s2() // b=a*2 18   a 9 

console.log(a,b) // 12 18

generator의 생성값


이전 절에서는 주로generator가 값을 생성하는 방식을 소개했는데 이 절에서는 더욱 기초적인 것을 소개할 것이다.

iterator


만약에 당신이 일련의 값을 생성하려고 한다면 모든 값은 이전과 특정한 관계를 가진다. 이것이 바로 교체 과정이다.iterator는generator에서 한 걸음 한 걸음 일련의 값을 얻을 수 있도록 정의된 좋은 인터페이스입니다.generator에서 다음 값을 얻으려면 호출해야 합니다*bar().

함수 클러치로 교체기를 구성하다


우리는 간단한 함수 패키지 구조로 숫자의 교체 과정을 생성할 수 있다.
const gimmeSomething = (() => {
    let nextVal;
    return () => {
        if (nextVal === undefined) {
            nextVal = 1
        } else {
            nextVal = (3 * nextVal) + 6
        }

        return nextVal
    }
})()

gimmeSomething() //1
gimmeSomething() //9
gimmeSomething() // 33
...

우리는 next() 인터페이스를 하나 더 구성합니다.
const something=(()=>{
    let nextVal
    return {
        [Symbol.iterator]:function(){return this}, //
        next:()=>{
            if(nextVal===undefined){
                nextVal=1
            }else{
                nextVal=nextVal*3+6
            }
            return {done:false,value:nextVal}
        }
    }
})()

자동 교체
es6에 추가된 next() 순환은 자동으로 표준 교체기를 교체할 수 있습니다.
for (var v of something) {
    console.log(v)
    if (v > 300) break;
}

// 1 9 33 105 321

다음 예제를 변경합니다.
const something = (() => {
    let nextVal
    return {
        [Symbol.iterator]: function() {
            return this
        },
        next: () => {
            if (nextVal === undefined) {
                nextVal = 1
            } else {
                nextVal = nextVal * 3 + 6
            }
            return {
                done: nextVal>300,
                value: nextVal
            }
        }
    }
})()

for (var v of something) {
    console.log(v) // 1 9 33 105
}
for...of 순환은 매번 교체할 때마다 자동으로 호출됩니다 for..of... 순환은 next() 에 어떤 값도 전송되지 않으며 next() 받아들일 때 멈춥니다.
사용자 정의iterator를 구성하는 것 외에 그룹에도 기본 교체기가 있습니다.
const a=[1,5,15,25]

for (var v of a) {
    console.log(v) // 1,5,15,25
}

일반적인object는 done:true 같은 기본 교체기가 없습니다. 대상의 모든 속성을 교체하려면 array 을 통해array를 되돌려주고 Object.keys(..) 이 키 명수 그룹을 교체합니다. (주의: for..of.. 는 원형 체인에서 온 속성을 포함하지 않습니다. Object.keys 는 포함됩니다.

2.iterable


iterable은 그 값에 교체할 수 있는 교체기를 포함하는 대상을 가리킨다. 그의 이름은 기호값for..in..이다. 이 함수를 호출할 때 교체기를 되돌려준다.Symbol.iterator 순환 자동 호출 for..of 함수로 교체기를 구축합니다.
이전 절에서 사용한 Symbol.iterator 교체수 그룹의 예는
const a=[1,5,15,25]

const it=a[Symbol.iterator]()

it.next().value //1
it.next().value //5
it.next().value // 15

3. 생성기 교체기


우리는genrator를 하나의 값의 생산자로 볼 수 있으며, 우리는 교체기 인터페이스 for..of 를 통해 한 번에 하나의 값을 추출할 수 있다.
generator를 실행할 때iterator를 얻을 수 있습니다.우리는 next()로 이전 무한 디지털 서열 생산자generator를 실현했다.
function *something(){
    let nextVal
    while(true){
        if(nextVal===undefined){
            nextVal=1
        }else{
            nextVal=nextVal*3+6
        }
        yield nextVal
    }
}

일반적으로 우리는 js 프로그램을 작성할 때 something 을 사용하고 그 중에서 퇴출 문장이 없을 때 매우 나쁜 설계를 한다. 만약 생성기에 while(true) 이 있다면, 이러한 순환을 사용하는 것은 전혀 문제가 없다.생성기가 매번 교체될 때마다 멈추기 때문에, yield 을 통해 메인 프로그램이나 시간 순환 대기열로 되돌아옵니다.yield를 사용하여 이 생성기를 순환합니다.
for(let v of something()){
    console.log(v)
    if(v>300) break; // 1 9 33 105 321
}

우리는 우선 for..of을 사용해야만 generator -> iterator 교체를 할 수 있기 때문에 먼저 for .. of 생산자를 구성하여 something() 순환 교체를 할 수 있다.generator의 교체기iterable에도 for..of.. 함수가 있기 때문에iterable이기도 하다.

생성기 중지


위의 예에서generatorSymbol.iterator의 교체기 실례는 순환 중*something() 이후 영원히 정지 상태에 머무르는 것 같다.
사실상 break에서 순환하는'이상 종료'(조기 종료)는 통상적으로break,return 또는 미포획 이상으로 인해generator의 교체기에 신호를 보내서 종료시킨다.for..of 문장을 사용하여generator를 구축합니다. generator가 외부에서 끝났더라도finally의 문장은 실행됩니다. 자원을 정리할 수 있습니다. 예를 들어 다음과 같습니다.
function *something(){
    try{
    let nextVal
    while(true){
        if(nextVal===undefined){
            nextVal=1
        }else{
            nextVal=nextVal*3+6
        }
        yield nextVal
    }
    }
    finally{
        console.log('clean up')
    }
}

for(let v of something()){
    console.log(v)
    if(v>300) break; // 1 9 33 105 321 'clean up'
}

위의 예에서break는finally문장을 촉발한다.우리도 try..finally.. 수동으로 생성기를 종료하는 교체기 실례를 사용할 수 있다.
const it=something()
for(let v of it){
    console.log(v)
    if(v>300){
        console.log(
            it.return('end up!!').value
            )
        //  break
    }
}
// 1 9 33 105 321
// clean up!
// end up!!
it.return()를 호출하면 생성기를 즉시 종료하고finally의 문장을 터치하며 되돌아오는 value를 it.return()에 전송된 내용으로 설정하고done는true, 즉 return()가 전송되는 과정, end up! 순환이 종료됩니다.

좋은 웹페이지 즐겨찾기