0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WebフロントエンドAdvent Calendar 2024

Day 20

ジェネレータとyield文

Last updated at Posted at 2024-12-21

はじめに

この記事は以下の記事の続きになります。

本記事では、イテレータを返す関数である、ジェネレータ関数と、ジェネレータ関数内で使用できるyield文についてみていきます。

ジェネレータ

ジェネレータは反復可能なオブジェクトであり、イテレータでもあります。
ジェネレータは、ジェネレータ関数によって生成されます。

ジェネレータ関数はfunction*によって定義します。
この関数は呼び出しても関数自体が実行されるのではなく、ジェネレータが返されます。

ジェネレータが通常のイテレータと異なるのは、next()メソッドを呼び出した時に、ジェネレータ関数の最初からyield文までが実行される点にあります。次にnext()が呼ばれた時には、前回のyieldの後からその次のyield文までが実行されます。

function* generatorFn () {
    console.log('start')
    yield 1
    console.log('after yield 1')
    yield 2
    console.log('after yield 2')
    yield 3
    console.log('after yield 3')
}

const generator = generatorFn()

console.log(generator.next().value)
console.log('stopped')
console.log(generator.next().value)
console.log('stopped')
console.log(generator.next().value)
console.log('stopped')
console.log(generator.next().value)
"start" 
1 
"stopped" 
"after yield 1" 
2 
"stopped" 
"after yield 2" 
3 
"stopped" 
"after yield 3" 
undefined 

この例から、ジェネレータのnext()が呼び出されるたびに、ジェネレータ関数のyield文までが実行されていることが分かります。

ジェネレータ関数の宣言

ジェネレータ関数はfunction*で宣言できます。
他にも、関数式やメソッドの形で宣言することもできます。

//関数式での宣言
const generatorFn = function* () {
    yield 1
    yield 2
    yield 3
}

メソッドの形で宣言する場合は、メソッド名の先頭に*をつけてジェネレータ関数であることを明示します。

const obj = {
    *generatorFn() {
        yield 1
        yield 2
        yield 3
    }
}
const generator = obj.generatorFn()

なお、アロー関数の形式でジェネレータ関数を宣言することはできません。

ジェネレータで書き換え

前回の記事で作成した以下の反復可能オブジェクトを、ジェネレータを使って書き換えてみます。

const iterableObject = {
    [Symbol.iterator]() {
        const random = Math.floor(Math.random() * 10) // 0から9の整数値をランダムに生成
        let restNum = random
        return {
            next() {
                restNum++
                if (restNum < 10) {
                    return { done: false, value: restNum }
                } else {
                    return { done: true, value: undefined }
                }
            }

        }
    }
}

console.log([...iterableObject])

イテレータを返す関数は、ジェネレータ関数を使って以下のように書き換えられます。

const iterableObject = {
    *[Symbol.iterator]() {
        const random = Math.floor(Math.random() * 10) 
        let restNum = random
        
        while (restNum < 10) {
            yield restNum++
        }
    }
}

console.log([...iterableObject])

[Symbol.iterator]()メソッドをジェネレータ関数に書き換えることで、next()next()の返り値である反復結果オブジェクト{done: false, value: restNum}は、yield文によって簡潔に書けるようになっています。

また、ジェネレータ関数によって[Symbol.iterator]()自体を使わずに書き換えることもできます。

const iterableObject = {
    *generatorFn() {
        const random = Math.floor(Math.random() * 10) 
        let restNum = random
        
        while (restNum < 10) {
            yield restNum++
        }
    }
}

console.log([...iterableObject.generatorFn()])

この書き換え方では、呼び出し方は変わるものの、[Synbol.iterator](){...}を宣言しなくて済むようになっています。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?