前の記事で説明したジェネレーターの動作は 複雑ではありませんが、それは間違いなく驚くべきことであり、最初は混乱しているように見えるかもしれません。したがって、新しい概念を学習する代わりに、一時停止して、ジェネレーターの使用の興味深い例を見ていきます。
次のような関数を作成しましょう。
function maybeAddNumbers() {
const a = maybeGetNumberA();
const b = maybeGetNumberB();
return a + b;
}
関数
maybeGetNumberA
と
maybeGetNumberB
戻り値ですが、
null
またはを返す 場合もあり
undefined
ます。これは、彼らの名前に「たぶん」という言葉が含まれていることからも明らかです。これが発生した場合は、これらの値(たとえば、数値と
null
)を入力しようとしないでください。たとえば、 停止して戻ることをお勧めし
null
ます。つまり
null
、
null
/
undefined
に数値または他の
null
/を 追加することによって得られる予測できない値ではありません
undefined
。
したがって、数値が実際に定義されていることを確認する必要があります。
function maybeAddNumbers() {
const a = maybeGetNumberA();
const b = maybeGetNumberB();
if (a === null || a === undefined || b === null || b === undefined) {
return null;
}
return a + b;
}
すべてが動作しますが、それは場合
a
である
null
か
undefined
、そして、関数を呼び出しても意味がありません
maybeGetNumberB
。とにかく返されることはわかっています
null
。
関数を書き直してみましょう:
function maybeAddNumbers() {
const a = maybeGetNumberA();
if (a === null || a === undefined) {
return null;
}
const b = maybeGetNumberB();
if (b === null || b === undefined) {
return null;
}
return a + b;
}
そう。単純な3行のコードの代わりに、すぐに10行に膨らませました(空のコードは数えません)。そして、関数が適用されました
if
。関数が何をするのかを理解するために、それを通り抜ける必要があります。そして、これは単なる教育的な例です!はるかに複雑なロジックを備えた実際のコードベースを想像してみてください。このようなチェックはさらに困難になります。ここでジェネレーターを使用して、コードを簡略化したいと思います。
見てください:
function* maybeAddNumbers() {
const a = yield maybeGetNumberA();
const b = yield maybeGetNumberB();
return a + b;
}
私たちは、発現させことができれば
yield <smething>
、それがある場合は、テストを
<smething>
実際の値ではなく、
null
か
undefined
?数値ではないことが判明した場合
null
は、前のバージョンのコードと同様に、停止して戻るだけ です。
つまり、実際の定義された値でのみ機能するように見えるコードを記述でき ます。ジェネレーターはこれをチェックし、適切なアクションを実行できます。魔法でしょ?そしてそれは可能であるだけでなく、書くのも簡単です!
もちろん、ジェネレータ自体にはこの機能はありません。それらはイテレータを返すだけであり、必要に応じて値をジェネレータに挿入して戻すことができます。したがって、ラッパーを作成する必要があり
runMaybe
ます。
関数を直接呼び出す代わりに:
const result = maybeAddNumbers();
これをラッパー引数と呼びます。
const result = runMaybe(maybeAddNumbers());
このパターンは、ジェネレーターで非常に一般的です。彼ら自身はあまり知りませんが、自作のラッパーの助けを借りて、ジェネレーターに望ましい動作を与えることができます!これが私たちが今必要としているものです。
runMaybe
-1つの引数を取る関数:ジェネレーターによって作成されたイテレーター:
function runMaybe(iterator) {
}
このイテレータをループで実行してみましょう
while
。これを行うには、イテレータを初めて呼び出して、そのプロパティのチェックを開始する必要があります
done
。
function runMaybe(iterator) {
let result = iterator.next();
while(!result.done) {
}
}
ループ内には、2つの可能性があります。
result.value
が
null
またはの 場合
undefined
、反復をすぐに停止して、を返す必要があります
null
。これをやろう:
function runMaybe(iterator) {
let result = iterator.next();
while(!result.done) {
if (result.value === null || result.value === undefined) {
return null;
}
}
}
ここでは、ヘルプ
return
を使用して反復を すぐに停止し、ラッパーから戻ります
null
。しかし、それ
result.value
が数値の場合 は、ジェネレーターに「戻る」必要があります。たとえば、
yield maybeGetNumberA()
関数
maybeGetNumberA()
が
yield maybeGetNumberA()
数値の場合、その数値の値を置き換える必要があります 。私に説明してみましょう:のは、計算の結果は言わせ
maybeGetNumberA()
、その後、我々は置き換え、5である
const a = yield maybeGetNumberA();
と
const a = 5;
。ご覧のとおり、抽出された値を変更する必要はありません。ジェネレータに戻すだけで十分 です。 メソッドに引数として渡すことで、ある値に
置き換えることができることを覚えています。
yield <smething>
next
イテレータ内:
function runMaybe(iterator) {
let result = iterator.next();
while(!result.done) {
if (result.value === null || result.value === undefined) {
return null;
}
// we are passing result.value back
// to the generator
result = iterator.next(result.value)
}
}
ご覧のとおり、新しい結果は再び変数に格納されます
result
。これは、を
result
使用して明確に宣言した ために可能
let
です。
ここで、値を取得するときにジェネレーターが
null
/ に遭遇した場合 、ラッパーから
undefined
戻るだけ です。 / を検出せずに反復プロセスが終了するように、他に何かを追加する必要があります 。結局のところ、2つの数値を取得した場合、ラッパーからそれらの合計を返す必要があります。 ジェネレータ は式で終了します 。私たちはその存在を理解しています
null
runMaybe
null
undefined
maybeAddNumbers
return
return <smething>
ジェネレーターで、呼び出しから
next
オブジェクト を返します
{ value: <smething>, done: true }
。これが発生
while
すると、プロパティ
done
が値を取得するため、ループ が停止 します
true
。ただし、最後に返された値(この特定のケースではこれ
a + b
)は引き続きプロパティに格納されます
result.value
!そして、私たちはそれを返すことができます:
function runMaybe(iterator) {
let result = iterator.next();
while(!result.done) {
if (result.value === null || result.value === undefined) {
return null;
}
result = iterator.next(result.value)
}
// just return the last value
// after the iterator is done
return result.value;
}
そしてそれがすべてです!
関数
maybeGetNumberA
とを作成 し
maybeGetNumberB
、最初に実数を返すようにします。
const maybeGetNumberA = () => 5;
const maybeGetNumberB = () => 10;
コードを実行して結果をログに記録しましょう。
function* maybeAddNumbers() {
const a = yield maybeGetNumberA();
const b = yield maybeGetNumberB();
return a + b;
}
const result = runMaybe(maybeAddNumbers());
console.log(result);
予想通り、数15は、コンソールに表示されます。
さて、との条件のいずれかを交換してください
null
:
const maybeGetNumberA = () => null;
const maybeGetNumberB = () => 10;
コードを実行すると、次のようになります
null
。
ただし、/を 返す
maybeGetNumberB
場合は、関数が呼び出されない ようにすることが重要です 。計算が成功したことをもう一度確認しましょう。これを行うには、2番目の関数に追加するだけです 。
maybeGetNumberA
null
undefined
console.log
const maybeGetNumberA = () => null;
const maybeGetNumberB = () => {
console.log('B');
return 10;
}
ラッパーを正しく記述している
runMaybe
場合、このコードを実行すると、文字 はコンソールに表示され
B
ません。
実際、コードを実行すると、単純にが表示され
null
ます。これは、ラッパーが
null
/を 検出するとすぐにジェネレーターを実際に停止することを意味します
undefined
。
コードは意図したとおりに機能します。
null
任意の組み合わせを生成し ます。
const maybeGetNumberA = () => undefined;
const maybeGetNumberB = () => 10;
const maybeGetNumberA = () => 5;
const maybeGetNumberB = () => null;
const maybeGetNumberA = () => undefined;
const maybeGetNumberB = () => null;
等。
しかし、この例の利点は、この特定のコードの実行にありません。これは、値/ を抽出できる任意のジェネレーターで 動作できるユニバーサルラッパーを 作成したという事実にあります 。 より複雑な関数を書いてみましょう。
null
undefined
function* maybeAddFiveNumbers() {
const a = yield maybeGetNumberA();
const b = yield maybeGetNumberB();
const c = yield maybeGetNumberC();
const d = yield maybeGetNumberD();
const e = yield maybeGetNumberE();
return a + b + c + d + e;
}
あなたは問題なく私たちのラッパーでそれを行うことができます
runMaybe
!実際、関数が数値を返すことはラッパーにとっても重要ではありません。結局のところ、数値型については触れていません。したがって、ジェネレーターで任意の値(数値、文字列、オブジェクト、配列、より複雑なデータ構造)を使用でき、ラッパーで機能します。
これが開発者を刺激するものです。ジェネレーターを使用すると、コードにカスタム機能を追加できます。これは非常に一般的に見えます(もちろん、呼び出しは別として
yield
)。ジェネレーターを特別な方法で反復するラッパーを作成する必要があります。したがって、ラッパーはジェネレーターに必要な機能を追加します。これは何でもかまいません。発電機にはほぼ無限の可能性があります。それはすべて私たちの想像力に関するものです。