コレクションで各アイテムを処理することは非常に一般的な操作です。 JavaScriptは、コレクションをシンプルに、および各ループに対してMap()、Filter()、Array comprehensions(配列派生)に至るまで、コレクションを反復する多くの方法を提供します。 JavaScript 1.7では、反復因子と発電機がCore JavaScriptの構文に新しい反復メカニズムをもたらし、また、各ループの挙動をカスタマイズするメカニズムを提供します。
イテレーター
イテレーターは、毎回コレクションシーケンスの要素にアクセスし、そのシーケンスの現在の反復位置を追跡するオブジェクトです。 JavaScript Iteratorは、次の要素をシーケンスで返す次の()メソッドを提供するオブジェクトです。この方法は、シーケンス内のすべての要素が通過すると、停止例外をスローします。
Iteratorオブジェクトが作成されると、次の()を明示的に繰り返すか、javaScriptを使用して…inおよび各ループに対して、暗黙的に呼ばれます。
Iterator()を使用して、オブジェクトと配列を繰り返す単純なイテレーターを作成できます。
コードコピーは次のとおりです。
var lang = {name: 'javascript'、Birthndyear:1995};
var it = iterator(lang);
初期化が完了すると、次の()メソッドを呼び出して、オブジェクトのキー価値ペアに順番にアクセスできます。
コードコピーは次のとおりです。
var pair = it.next(); // key-valueペアは["name"、 "javascript"]です
pair = it.next(); //キー価値ペアは[「誕生日」、1995]です
pair = it.next(); // `stopiteration`例外がスローされました
for…inループを使用して、明示的な呼び出しを次の()メソッドに置き換えることができます。停止例外がスローされると、ループは自動的に終了します。
コードコピーは次のとおりです。
var it = iterator(lang);
for(その中のvarペア)
印刷(ペア); // 1つの[key、value] keyvalueペアは毎回出力されます
オブジェクトのキー値を繰り返したい場合は、2番目のパラメーターをiterator()関数に渡すことができます。
コードコピーは次のとおりです。
var it = iterator(lang、true);
for(その中のvarキー)
print(key); //出力キー値のみ
Iterator()を使用してオブジェクトにアクセスすることの利点の1つは、Object.prototypeに追加されたカスタムプロパティがシーケンスオブジェクトに含まれていないことです。
iterator()は、配列でも使用できます。
コードコピーは次のとおりです。
var langs = ['javascript'、 'python'、 'haskell'];
var it = iterator(langs);
for(その中のvarペア)
印刷(ペア); //反復出力のみ[index、language]キー値ペア
オブジェクトのトラバースと同様に、2番目のパラメーターとしてトラバーサルにtrueを渡す結果は、配列インデックスになります。
コードコピーは次のとおりです。
var langs = ['javascript'、 'python'、 'haskell'];
var it = iterator(langs、true);
(その中のvar i)
印刷(i); //出力0、1、2
LETキーワードを使用して、ループ内で変数を個別にブロックするインデックスと値を割り当てると、割り当て(割り当ての破壊)を破壊することもできます。
コードコピーは次のとおりです。
var langs = ['javascript'、 'python'、 'haskell'];
var it = iterators(langs);
for([私、ラング]を入れましょう)
print(i + ':' + lang); //出力 "0:javascript"など
カスタムイテレーターを宣言します
要素のコレクションを表すいくつかのオブジェクトは、指定された方法で反復する必要があります。
1。範囲(範囲)を表すオブジェクトを反復し、この範囲に含まれる数値を1つずつ返す必要があります。
2。深さfirstまたは幅の最初のものを使用して、ツリーのリーフノードにアクセスできます
3。結果セット全体が単一の配列にロードされていない場合でも、データベースクエリの結果を表すオブジェクトを反復する必要があります。
4.無限の数学シーケンス(Fibonacciシーケンスなど)に作用するイテレーターは、無限の長さのデータ構造を作成せずに結果を次々と返す必要があります。
JavaScriptを使用すると、反復ロジックをカスタマイズしてオブジェクトに適用するコードを作成できます
2つの値でシンプルな範囲オブジェクトを作成します。
コードコピーは次のとおりです。
関数範囲(低、高){
this.low = low;
this.high = high;
}
次に、範囲内のすべての整数のシーケンスを返すカスタムイテレーターを作成します。 Iteratorインターフェイスでは、シーケンスの次の要素を返すか、停止例外をスローするための次の()メソッドを提供する必要があります。
コードコピーは次のとおりです。
function remantitator(範囲){
this.range = range;
this.current = this.range.low;
}
rishiTerator.prototype.next = function(){
if(this.current> this.range.high)
停止を投げます。
それ以外
this.current ++を返します。
};
私たちの遠隔器は、現在のシーケンスの位置を追跡するための現在のプロパティを維持しながら、範囲インスタンスによってインスタンス化されます。
最後に、範囲を範囲と組み合わせるために、範囲に特別な__iterator__メソッドを追加する必要があります。範囲を繰り返しようとすると、それは呼び出され、反復ロジックを実装するrangeTeratorのインスタンスを返す必要があります。
コードコピーは次のとおりです。
range.prototype .__ iterator__ = function(){
new rangeriterator(this)を返します。
};
カスタムイテレーターを完了した後、スコープインスタンスを反復させることができます。
コードコピーは次のとおりです。
var range = new Range(3、5);
for(範囲のvar i)
印刷(i); //出力3、4、5
ジェネレーター:イテレーターを構築するためのより良い方法
カスタムイテレータは便利なツールですが、明示的に維持する必要があるため、作成時に慎重に計画する必要があります。
ジェネレーターは強力な機能を提供します。独自の反復アルゴリズムを含む関数を定義でき、状態を自動的に維持できます。
ジェネレーターは、イテレーターファクトリーとして使用できる特別な機能です。関数に1つ以上の収量式が含まれている場合、それはジェネレーターと呼ばれます(翻訳者の注:node.jsも関数名の前に *で表現する必要があります)。
注:収量キーワードは、<script type = "application/javascript; version = 1.7">(または後)に含まれるHTMLのコードブロックにのみ使用できます。 XUL(XMLユーザーインターフェイス言語)スクリプトタグは、これらの機能にアクセスするためにこの特別なコードブロックを指定する必要はありません。
ジェネレーター関数が呼び出されると、関数本文はすぐに実行されません。ジェネレーター - 文字装置オブジェクトを返します。次の()ジェネレーター - 適性因子のメソッドが呼び出されるたびに、関数本体は次の得利子式に実行され、その結果を返します。関数が終了または遭遇すると、復帰ステートメントが発生すると、停止例外がスローされます。
例を使用して、よりよく説明します。
コードコピーは次のとおりです。
関数simplegenerator(){
「最初」を獲得します。
「2番目」を獲得します。
「3番目」を獲得します。
for(var i = 0; i <3; i ++)
I積はi;
}
var g = simpleGenerator();
print(g.next()); //出力 "first"
print(g.next()); //出力「second」
print(g.next()); //出力「3番目」
print(g.next()); //出力0
print(g.next()); //出力1
print(g.next()); //出力2
print(g.next()); //停止例外を投げます
ジェネレーター関数は、クラスで__iterator__メソッドとして直接使用でき、カスタムイテレーターが必要なコードの量を効果的に削減できます。ジェネレーターを使用して範囲を書き直しましょう。
コードコピーは次のとおりです。
関数範囲(低、高){
this.low = low;
this.high = high;
}
range.prototype .__ iterator__ = function(){
for(var i = this.low; i <= this.high; i ++)
I積はi;
};
var range = new Range(3、5);
for(範囲のvar i)
印刷(i); //出力3、4、5
すべてのジェネレーターが終了するわけではありません。無限のシーケンスを表すジェネレーターを作成できます。次のジェネレーターはフィボナッチシーケンスを実装します。このシーケンスでは、各要素が最初の2つの合計です。
コードコピーは次のとおりです。
functionfibonacci(){
var fn1 = 1;
var fn2 = 1;
while(1){
var current = fn2;
fn2 = fn1;
fn1 = fn1 + 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
ジェネレーター関数はパラメーターを使用でき、関数が初めて呼び出されたときにこれらのパラメーターを使用します。 returnステートメントを使用して、ジェネレーターを終了することができます(停止例外をスローさせます)。次のFibonacci()バリアントは、条件がトリガーされたときに関数を終了するオプションの制限パラメーターを取ります。
コードコピーは次のとおりです。
function fibonacci(lime){
var fn1 = 1;
var fn2 = 1;
while(1){
var current = fn2;
fn2 = fn1;
fn1 = fn1 + current;
if(limit && current>制限)
戻る;
降伏電流;
}
}
ジェネレーターの高度な機能
ジェネレーターは、要件に基づいて利回りの戻り値を計算できます。これにより、以前に高価なシーケンス計算要件、さらには上記の無限シーケンスを表すことができます。
次の()メソッドに加えて、Generator-iteratorオブジェクトにはsend()メソッドもあり、ジェネレーターの内部状態を変更できます。 send()に渡された値は、最後の収量発現の結果として扱われ、ジェネレーターは一時停止されます。 send()メソッドを使用して指定された値を渡す前に、ジェネレーターを起動するには、少なくとも1回は次()を呼び出す必要があります。
次のFibonacciジェネレーターは、send()メソッドを使用してシーケンスを再起動します。
コードコピーは次のとおりです。
functionfibonacci(){
var fn1 = 1;
var fn2 = 1;
while(1){
var current = fn2;
fn2 = fn1;
fn1 = fn1 + current;
var reset = evelow 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
注:興味深いことに、Send(未定義)を呼び出すことは、Next()を呼び出すのとまったく同じです。ただし、新しいジェネレーターを起動するためにsend()メソッドが呼び出されると、未定義を除いてタイプエラーの例外がスローされます。
スローメソッドを呼び出して、発電機に例外をスローするように強制するためにスローする外れ値を渡すことができます。この例外は現在のコンテキストからスローされ、現在の収量実行と同様にジェネレーターを一時停止しますが、スロー値ステートメントに置き換えられます。
例外をスローするプロセス中に収量が発生しない場合、例外はスロー()メソッドが呼び出されるまで渡され、その後、次の()を呼び出すと、停止例外がスローされます。
ジェネレーターには、発電機を強制的に終了させるための閉じる()方法があります。発電機の終了には、次の効果があります。
1.すべての有効な最終的に発電機の文は実行されます
2。最後に単語が停止以外の例外をスローする場合、例外はclose()メソッドの呼び出し者に渡されます。
3.ジェネレーターは終了します
ジェネレーター式
配列導出の明らかな欠点の1つは、配列全体がメモリ内で構築されることです。派生への入力のオーバーヘッドは、そのオーバーヘッドが小さな配列自体である場合は重要ではありませんが、入力配列が大きい場合、または新しい高価な(または無限の)アレイジェネレーターを作成するときに問題が発生する可能性があります。
ジェネレーターは、必要に応じて必要に応じて、レイジーコンピューティングが必要に応じて要素を計算できるようにします。発電機の式は、配列の派生とほぼ同じ構文であり、四角いブラケットの代わりに括弧を使用します(およびそれぞれの代わりに... in ... in for in in) - しかし、計算を遅らせることができるアレイの代わりにジェネレーターを作成します。ジェネレーターを作成するための簡単な構文と考えることができます。
整数の巨大なシーケンスを繰り返して反復剤を持っているとします。偶数を繰り返すために新しいイテレーターを作成する必要があります。配列の派生は、メモリ内のすべての偶数を含む配列全体を作成します。
コードコピーは次のとおりです。
var doubles = [i * 2 for(i in it)];
ジェネレーターの式は、新しいイテレーターを作成し、必要に応じて必要に応じて均等な値を計算します。
コードコピーは次のとおりです。
var it2 =(i * 2 for(i in it));
print(it2.next()); //最初の偶数
print(it2.next()); //その中の2番目の偶数
ジェネレーターが関数のパラメーターとして使用される場合、括弧は関数呼び出しとして使用されます。つまり、最も外側の括弧を省略できます。
コードコピーは次のとおりです。
var result = dosomething(i * 2 for(i in it));
終わり。