変数の場合の動作再帰の実装を理解する

行動変数の理解が 再帰を実装する

この問題はJavaScriptで再帰を実装したいと思い、またどのように変数理論JavaScriptでは、変数の型、あるいは変数の宣言を宣言する。必要はありませんそのような状況の下での動作を理解してほしい。たとえば、次のコードは完璧に動作します:

場合(カウンタ== 1)( バッファ ="カウンタは1です。";)("結果")Document.getElementByIdにて。innerHTML = バッファ;

バッファ変数の前に上記のコードで、ifブロックで宣言されませんでした。コードの最後の行は、バッファのinnerHTMLプロパティを割り当てる変数を使用します。宣言のこの種のため、バッファを定義するかもしれない問題です。 JavaScriptのエラーとして、これは触れていないし、innerHTMLの値はundefinedが代入されます。この例では、JavaScript内の変数の方法では、JavaやC#的背景を持つプログラマーに慣れていない可能性がありますに振る舞うことを示しています。このレシピの焦点は、どのように変数を別のコンテキストでの動作を把握しています。一例として、コンテキストをJavaScriptで再帰の実装です。ソリューションの2つの例の関数は、JavaScriptで次の再帰を実装しています。

 ソース: /サイト/ルート/ ajaxrecipes / javascriptに/ variablebehavior.html関数RecursionGlobal(カウンター)(情報("RecursionGlobal(localCounter)"、typeof演算(localCounter)); =カウンタlocalCounter;情報("RecursionGlobal(localCounter)"、localCounter);場合(localCounter"3)(RecursionGlobal(localCounter + 1);))関数(カウンター)(情報をもっと見るRecursionLocal("RecursionLocal(localCounter)"、typeof演算(localCounter)); ヴァール localCounter =カウンタ;場合(localCounter"3)(RecursionLocal情報("RecursionLocal(localCounter)"、localCounter);(localCounter + 1);))

この例では2つの方法:RecursionGlobalとRecursionLocal示しています。 2つのメソッドの間にある唯一の違いとして、太字のコードに示すように:JavaScriptのvarキーワードです。 1つのキーワードvar方法localCounter変数に格納されてバリエーションがあります。実行時に、両方のメソッドの動作は同じですし、同じ結果を生成しますまず、一目では、varキーワードを任意の目的を果たしていないと考えることがあります。しかし、これはvarキーワードは、次のプログラムを実行することによって説明されている目的は、提供しません:

情報:*** ***情報:RecursionGlobal(localCounter)不定情報:RecursionGlobal(localCounter)1情報:RecursionGlobal(localCounter)番号情報:RecursionGlobal(localCounter)2情報:RecursionGlobal(localCounter)番号情報:RecursionGlobal(localCounter開始recursion_global )3情報:*** ***情報:RecursionLocal(localCounter)不定情報:RecursionLocal(localCounter)1情報:スタートrecursion_local RecursionLocal(localCounter)不定情報:RecursionLocal(localCounter)2情報:RecursionLocal(localCounter)不定情報:RecursionLocal (localCounter)3
  

通知をしたときにRecursionGlobal関数は、最初の呼び出しのためのlocalCounterのタイプを実行し、定義され、その後は数です。対照的に、ときにRecurisonLocal関数は、localCounterのタイプごとに、すべての呼び出しに定義されて呼び出されます。

これは、ヴァール宣言の目的を果たすことを意味するが、そこから、それが宣言されている範囲にローカルな変数です。場合は、変数varキーワードと、その変数をグローバルスコープで宣言されられていません。再帰ループを作成する場合は、すべての場合には、varキーワードを使用する必要がありますが、それ以外のデータが破損することができます。次の例では、再帰を使って、スタックの内容を逆にする方法を示します。際、場合によっては再帰を使ってがないため参考値として以外の提供、関数のパラメータを宣言する必要があります。

 ソース: /サイト/ルート/ ajaxrecipes / javascriptに/ variablebehavior.html関数RecursiveStackOldWay(arrayToProcess、processedArray)(情報("RecursiveStackOldWay"、"--->スタート"); ="+(processedArray.("RecursiveStackOldWay"、"再帰的な深さ情報をもっと見る長さ+ 1));());場合(arrayToProcess.length"0)(RecursiveStackOldWay(arrayToProcess、processedArray)(arrayToProcess.pop processedArray.push;)情報("RecursiveStackOldWay"、"--->終了");)ヴァールarrayToProcess =新しいArray(); arrayToProcess.push("value2が");ヴァールprocessedArray =新しいArray("値1"); arrayToProcess.push()RecursiveOldWayStack(arrayToProcess、processedArray);

ここでは、RecursiveStackOldWay関数は2つのパラメータ:arrayToProcessとprocessedArrayしています。最初のパラメータは、arrayToProcessは、逆転される配列です。 2番目のパラメータは、processedArrayには、宛先スタックです。宛先ごとに再帰のパラメータとして、これは、関数がどこかでスタックを置くことができるに沿ってドラッグすることが必要なスタック呼び出し先のスタックとは、再帰関数に渡すことをインスタンス化するための責任がある。多くの場合、ただし、作成時に再帰的な関数場合は、最初の先頭で定義されている特定のパラメータレベルのコールを使用して関数をコールする必要があります。これらのパラメータは、まだ最初のトップレベルのコールの最初の呼び出しを行うには何もない(processedArray)を宣言する必要があります。一言で言えば、問題はそのときに、再帰的な関数を呼び出して、その次に、再帰によって使用される変数の設定を初期化する必要があります。この例では、初期化は、呼び出し側の責任です。これは、開発者はどのように特定のパラメータを理解するための関数にもかかわらず、彼らは、呼び出し元が使用できない場合がありますが必要なソリューションの作品が、それまでの最適化からです。もう1つのソリューションをしてパラメータを初期化し、再帰呼び出しは、再帰するためのラッパー関数を作成することです。

ラッパー関数は、今ではプログラマーの仕事は、再帰関数のラッパー関数を維持しています。JavaScriptの3分の1のソリューションを提供:再帰関数自体を初期化することができます。問題は、どのように再帰関数はこれが初めてと呼ばれている知っている? JavaやCのような伝統的なプログラミング言語では#、Boolean型のパラメータを定義するだろうと、最初の呼び出しを示すためにtrueに設定して、任意の後続の呼び出しを示すためにfalseを返します。これは、パラメータ自体されているJavaScriptのソリューションは、フラグやインジケータを必要としない指標。場合は、RecursiveOldWayStack関数の実装としては、コードが呼び出しRecursiveOldWayStack似ているがままの例については、想像は、次の:

ヴァールarrayToProcess =新しいArray(); arrayToProcess.push("value2が");ヴァールprocessedArray = RecursiveOldWayStack(arrayToProcess);("value1が"); arrayToProcess.push

変更の実装では先のスタックをインスタンス化するための責任ではなく、発信者です。その責任をRecursiveOldWayStack機能するために委任されている。ためRecursiveOldWayStackを初期化して、再帰を開始する必要がありますしかし、問題が発生します。このソリューションは、JavaScriptによって使用されるかどうかを、2番目のパラメータは、次の変形関数RecursiveStackと呼ばれるに示すように定義されて決定することです。

 ソース: /サイト/ルート/ ajaxrecipes / javascriptに/ variablebehavior.html関数RecursiveStack(arrayToProcess、processedArray)(情報("RecursiveStack"、"--->スタート"); 場合は((processedArray)=="undefined"を)typeof演算( インフォメーション("RecursiveStack"、"")頭文字<イニシャル; processedArray =新しいArray(); RecursiveStack(arrayToProcess、processedArray); インフォメーション("RecursiveStack"、"--->終了"); 戻りprocessedArray; 他の(情報("RecursiveStack"、"再帰的な深さ="+(processedArray.length + 1));());場合(arrayToProcess.length"0)(RecursiveStack(arrayToProcess、processedArray)(arrayToProcess.pop processedArray.push; )情報("RecursiveStack"、"--->終了");を返す;))

変更の実装では、RecursiveStack関数の期待を実装しています期待されている場合、この関数は1つのパラメータを使用し、それを呼び出し元に、再帰の最初の呼び出しを行っていると呼ばれ、そうでない場合は、再帰が起こっている。かどうかの最初の呼び出しの太字のコードによって決定されます起こっていることを知って期待。場合は、2番目のパラメータは、processedArray、未定義の場合、再帰的な関数自体を初期化し、再帰を開始します。場合は、2番目のパラメータが定義され、それが起こっており、再帰と想定されている機能などの前に我々が続けば、事実RecursiveStack 2つのパラメータが摘発された場合は、データが処理されますが、1と呼ばれています。

以前の私の期待についての話は、呼び出し元の2つのパラメータを渡す必要があります。この例では、呼び出し元の2つのパラメータを渡す必要はないと言うのではなく、この例では、呼び出し元が2つのパラメータを渡すにしないと述べて、この関数の機能を補償する必要があります。同じ機能の初期化に使用することができます期待に基づいている場合は、呼び出し元に、2番目のパラメータを定義して、責任を初期化を実装するために講じている側を意味再帰。呼び出し側では、RecursiveStack初期化を実行しないと初期化の定義に直接再帰機能にジャンプします。

このソリューションの利点は、明示的にラッパー関数を定義することなく、多機能を持っています。あなたは、"もちろん、この可能性、JavaやCなどの言語を使用している関数のオーバーロードを使用して#考えていることがあります。"はい、それは可能性がオーバーロードされた関数を使用するが、前述したように、オーバーロードされた関数は、実際の実装を呼び出すラッパー関数ですを意味する2つの関数が必要に書き込まれると主張した。 JavaScriptでは、すべて1つの自己関数が含まれに包まれていることが、今は、再帰を実装したと、ローカルスコープの変数をグローバルスコープの変数との間の違いを知って、次の質問がある場合は2つの変数は、何が起こるのです同じ名前?は、どのようなグローバルとローカル変数の宣言のスコープはどうなるのグローバルスコープ内に存在するローカルスコープ内で変数を定義するのだろう?次のコードをどのように変数をグローバルに1つの関数で定義され、その後、別の関数で参照されています。

 ソース: /サイト/ルート/ ajaxrecipes / javascriptに/ variablebehavior.html関数GlobalScope()(情報("GlobalScope()"、typeof演算())scopedVariable scopedVariable; scopedVariable ="globalscope";("GlobalScope()"scopedVariable、"="scopedVariable + scopedVariable +➥"タイプ="+ typeof演算(scopedVariable))インフォメーション;)関数testScopeという()(情報("OtherScope()"scopedVariable、"scopedVariable ="+ scopedVariable +"タイプ="➥+ typeof演算()scopedVariable);)

scopedVariable GlobalScopeで定義されtestScopeというのを参照しました。がないので、VARが- GlobalScopeでscopedVariableの宣言に基づく、scopedVariableグローバルスコープに配置されます。 GlobalScope scopedVariableになります後testScopeという上映グローバルには、次の生成された出力に示すように定義される:

情報:GlobalScope()は未定義情報scopedVariable:GlobalToLocalScope()scopedVariable = globalscopeタイプ=文字列の情報:scopedVariable testScopeという()scopedVariable = globalscopeタイプ=文字列scopedVariable

生成された出力では、GlobalScopeと呼ばれ、実装された関数の先頭で、scopedVariableは未定義です。次にscopedVariable、およびバッファが割り当てられて生成される出力は、scopedVariable定義されていないと参照の文字列を示します。testScopeというの呼び出しは、scopedVariableグローバルであると示してバッファが割り当てられて、今と同じ例を考えます。除き、グローバルスコープの変数として再宣言されローカル変数はvarキーワードを使用する。

 ソース: /サイト/ルート/ ajaxrecipes / javascriptに/ variablebehavior.html関数AlwaysLocalScope()(情報("GlobalToLocalScope()"、typeof演算())scopedVariable; ="AlwaysLocalScope";情報をもっと見るscopedVariable("GlobalToLocalScope()"scopedVariable、"= scopedVariable scopedVariable "+ scopedVariable +➥"タイプ="+ typeof演算(scopedVariable)); ヴァールscopedVariable;

関数の実装では、scopedVariable最初に、これはvarキーワードを使用していないバッファが割り当てられます。したがって、scopedVariableグローバルスコープレベルで宣言されます。あるいは、少なくともを信じるように何を主導している。何が起こるため、関数の最後の命令(太字)をローカルにするscopedVariable変数を宣言し、その変数はローカルレベルで宣言されています。これは、変数が宣言されている場合はどこかの関数は、varでローカルにするには奇妙に思えることがありますキーワードが使用されます。場合には、varキーワードは、実行されることはありません決定ブロック内で使用されてさえ、それは、変数は、ローカル宣言されてodderを取得します。説明するためには、最初にAlwaysLocal関数が呼び出されますtestScopeという、これは、次の出力を生成します:

情報:AlwaysLocalScope()は未定義情報scopedVariable:AlwaysLocalScope()scopedVariable = AlwaysLocalScopeタイプ=文字列を警告:一般的なエラー(scopedVariable定義されていない場合)scopedVariable

時AlwaysLocalScope関数が呼び出され、scopedVariable定義され、それもグローバルもローカルスコープ内に存在するを意味します。その時、変数に代入されると、生成された出力値と型を持ちます。これscopedVariable定義されていないときはtestScopeという関数が呼び出されると、例外が発生します。輸送するときに変数をグローバルスコープで宣言され、ローカルスコープ内の知っている。最後のテストのときに何の変数も、グローバルとローカルスコープ内で宣言されて起こるのか見ています。テストでは、シーケンス内の関数の呼び出しが含ま:GlobalScope、testScopeという、AlwaysLocalScopeし、testScopeという。このシーケンスを呼び出すと、次の出力を生成します:

情報:GlobalScope()は未定義情報scopedVariable:GlobalScope()scopedVariable = globalscopeタイプ=文字列の情報:scopedVariable testScopeという()scopedVariable = globalscopeタイプ=文字列の情報:scopedVariable AlwaysLocalScope()は未定義情報scopedVariable:AlwaysLocalScope()scopedVariable = AlwaysLocalScopeタイプ=文字列scopedVariable情報:testScopeという()scopedVariable = globalscopeタイプ=文字列scopedVariable

生成された出力では、scopedVariable宣言されてGlobalScopeに割り当てられます。 testScopeという関数は、scopedVariable存在を確認します。その後、AlwaysLocalScopeの呼び出しは、varは、関数内でscopedVariableへの参照はローカル変数の参照を宣言します。従って、存在する場合、グローバルに同じ名前を持つ変数を定義し、その関数のスコープ内でアクセスされていません。あなたが(それは、インライン関数ではありません)を意味し、グローバルスコープの変数を割り当てるを参照するグローバル変数の2つの方法:ウィンドウのプロパティを介して参照するか、実行中の関数の外部にある関数を作成しているときは、変数は、typeof割り当てられていない関数はundefinedを返します。

一度変数に割り当てると、typeof演算を別の値が返されます。場合、変数は関数のコンテキストでは、それぞれ、すべての時間は、関数、変数の前に割り当てられて定義されると定義されます。次のようにグローバルなレベルでは、変数には、delete演算子を使用して、:を削除scopedVariable;通常、演算子を削除するオブジェクトのプロパティをリセットするために使用される設定を解除することができます。いつ削除する識別子は、グローバル変数の参照に使用されて削除されます。あなたが削除機能を使用して参照を削除することはできません。の範囲の別のバリエーション動的なコードを使ってテストしましょう。 JavaScriptでは、eval関数を使用しているときは、変数およびグローバルスコープとみなされるときに、ローカルスコープとみなされるテストには、JavaScriptのバッファが実行されます。 AlwaysLocalScope機能により変更されます。最初のバリエーションについては、AlwaysLocalScope動的に割り当てる必要があります:

関数AlwaysLocalScope()(情報("AlwaysLocalScope()"、typeof演算(scopedVariable))scopedVariable; eval("scopedVariable ='AlwaysLocalScope'");インフォメーション("AlwaysLocalScope()"、"="scopedVariable + scopedVariable +➥"タイプ="+ typeof演算(scopedVariable));ヴァールscopedVariable;)scopedVariable

変更されたコードは太字で、scopedVariableの割り当てを示すように実行されます。このようにevalを用いても効果はありませんし、コードの動的な実行の場合と同様に、コードが変更されていたのと同じです。 evalで利点は、テキストバッファにして、コードの一部を割り当てることができますバッファを実行される。これはvarキーワードは、関数宣言内に存在するscopedVariableのスコープが変更されていない。宣言時には、JavaScriptのプロセッサによっては、ローカル変数の宣言の中で、結果が解析されます。ローカル宣言の動作を変更する方法の一つevalステートメントでは、次のコードの修正に示すように、変数の宣言を埋め込むことです:

関数AlwaysLocalScope()(情報("AlwaysLocalScope()"、typeof演算(scopedVariable))scopedVariable; eval("scopedVariable ='AlwaysLocalScope'");インフォメーション("AlwaysLocalScope()"、"="scopedVariable + scopedVariable +➥"タイプ="+ typeof演算(scopedVariable))scopedVariable; eval("ヴァールscopedVariable;");

元AlwaysLocalScopeコードを尊重するとの修正コードを太字で表示されます。このとき、両方の割り当てとscopedVariableダイナミックでの宣言は、scopedVariableときに割り当てられた意味をグローバル変数として扱われます。これは、最初のeval文が実行されますこれは、あるscopedVariableのない申告書とされているJavaScriptランタイムは、グローバル空間でscopedVariable格納することです。動作を変更するとscopedVariableローカル変数として宣言すると、AlwaysLocalScopeニーズにもっと時間を変更する次のように:

関数AlwaysLocalScope()(情報("AlwaysLocalScope()"、typeof演算(scopedVariable))scopedVariable; eval("ヴァールscopedVariable;"); eval("scopedVariable ='AlwaysLocalScope'");インフォメーション("AlwaysLocalScope()"、"="scopedVariable + scopedVariable +➥"タイプ="+ typeof演算(scopedVariable))scopedVariable;)

最新の変更では、最初のevalの宣言はvarキーワードを使用してscopedVariable。ローカル変数としてscopedVariableの宣言の中で最初のeval呼び出しの結果。 2番目のevalの呼び出しは、ローカル変数のスコープが設定さscopedVariableに値を代入するときの関数のコンテキスト内で変数を宣言またはグローバルスコープでは、心の中で、次の点を維持:

•ある変数に2つのスコープ:関数と、グローバルにローカルです。

ローカル変数•varキーワードを使用して、例外をグローバルな文脈で、varの使用されると宣言されます。 varの使用は、関数の冒頭にする必要はありません。

グローバル変数•ときに、変数にはvarキーワードを使用せずに割り当てられて宣言されます。

•これは、グローバルレベルのスコープでは、varキーワードを使用して変数を宣言することはお勧めです。

•ローカルと同じ名前のグローバル変数が互いに上書きされません。ローカルで宣言された変数を非表示にグローバルに同じ名前を持つ変数を宣言した。

•ときは、変数、typeof演算は未定義の変数の結果を使用して宣言されていません。

•現在のグローバル変数はdelete演算子を使用して設定を解除することができます。

•ときは、使用する必要が再帰的な関数を使って、ローカル変数を宣言した。

•再帰は、通常の初期化および実行が含まれます。 JavaScriptでは、初期化および実行を使用して、単一の関数にラップすることができます。

•ラップの初期化と1つの関数の実行の期待ここで、変数の可用性を呼び出してコンテキストを決定するためにテストされて使用されます。

•をeval動的にローカルまたはグローバル変数を宣言するために使用することが可能です。

•使用evalは先読みするとき、ローカル変数を識別する実行しないように、JavaScriptのプロセッサになります。したがって、ローカル変数を宣言するには、varキーワードを変数に代入する前に使用される必要があります。

•evalステートメントを使用して、プログラムが動的かどうかの変数はローカルスコープまたはグローバルスコープで宣言されるかを決めることができます。

記事は、ソニアLandeを提出


免責事項:弊社のウェブサイトは、この資料の内容については責任を負いません。 Webarticles無料の情報リソースです。
重要: この記事は、"変数が"自動ソフトウェアによって翻訳された再帰の実装の動作を理解する。大変申し訳ございませんが発生した可能性があります任意のスペルミスを感じている。お客様のご理解いただき、ありがとうございます。


Online: 263 users browsing the articles directory