web-dev-qa-db-ja.com

JavaScript変数はループの外側または内側を宣言しますか?

AS3では、パフォーマンスを向上させるために、ループ外のすべての変数を初期化する必要があると思います。これはJavaScriptでも同様ですか?どちらが良い/速い/ベストプラクティスですか?

var value = 0;

for (var i = 0; i < 100; i++)
{
    value = somearray[i];
}

または

for (var i = 0 ; i < 100; i++)
{
    var value = somearray[i];
}
204
davivid

JavaScriptまたはActionScriptには、意味またはパフォーマンスに絶対差なしがあります。

varはパーサーのディレクティブであり、notは実行時に実行されるコマンドです。関数body(*)のどこかで特定の識別子がvarで1回以上宣言されている場合、ブロック内のその識別子のすべての使用はローカル変数を参照します。 valueがループ内でvarとして宣言されているか、ループ外で宣言されているか、またはその両方であるかにかかわらず、違いはありません。

そのため、最も読みやすいと思うものを書いてください。関数の最上部にすべての変数を配置することが常に最善であるという点で、Crockfordには同意しません。コードのセクションで変数が一時的に使用される場合は、そのセクションでvarを宣言する方がよいので、セクションは単独でコピーアンドペーストできます。それ以外の場合、リファクタリング中に、関連するvarを個別に選択して移動することなく、数行のコードを新しい関数にコピーアンドペーストすると、偶発的なグローバルが発生します。

特に:

for (var i; i<100; i++)
    do something;

for (var i; i<100; i++)
    do something else;

Crockfordは、2番目のvarを削除することを推奨します(または、上記のvarsを削除し、上記のvar i;を実行します)。ただし、IMOでは、簡単に忘れてしまう余分なコードを関数の上部に置くのではなく、両方のvarsを保持し、関連するすべてのコードをまとめて保持する方が保守性が高くなります。

個人的には、同じ関数の他の部分で同じ変数名の別の使用があるかどうかに関係なく、コードの独立したセクションで変数の最初の割り当てをvarとして宣言する傾向があります。私にとっては、varを宣言することは、望ましくないJSいぼです(変数をデフォルトでローカルにした方がよかったでしょう)。 JavaScriptでもANSI Cの[古いリビジョン]の制限を複製することは私の義務ではないと思います。

(*:ネストされた関数本体以外)

271
bobince

言語にはブロックスコープはなく、関数スコープのみがあるため、理論的にはJavaScriptに違いはありません。

パフォーマンスの引数についてはわかりませんが、 Douglas Crockford は、varステートメントを関数本体の最初のステートメントにすることを推奨しています。 JavaScriptプログラミング言語のコード規約

JavaScriptにはブロックスコープがないため、ブロックで変数を定義すると、他のCファミリ言語の経験があるプログラマを混乱させる可能性があります。関数の上部ですべての変数を定義します。

次の例でわかるように、彼にはポイントがあると思います。関数の先頭で変数を宣言しても、変数iforループブロックのスコープ内に保持されていると考えるように読者を混乱させることはありません。

function myFunction() {
  var i;    // the scope of the variables is very clear

  for (i = 0; i < 10; i++) {
    // ...
  }
}
65
Daniel Vassallo

ECMA-/Javascript言語hoists関数の最上部のどこかに宣言されている変数。これは、この言語doesfunction scopeを持ち、notblock scopeを持っているため、他の多くのCライクな言語と同様です。
それはlexical scopeとも呼ばれます。

次のように宣言する場合

var foo = function(){
    for(var i = 0; i < 10; i++){
    }
};

これにより、hoistedが取得されます。

var foo = function(){
    var i;
    for(i = 0; i < 10; i++){
    }
}

したがって、パフォーマンスに違いはありません(ただし、ここで完全に間違っている場合は修正してください)。
not関数の最上部以外の場所で変数を宣言するためのはるかに優れた引数はreadabilityです。 for-loop内で変数を宣言すると、この変数はループ本体内でしかアクセスできないという誤った仮定になる可能性があります。これはまったく間違っているです。実際、現在のスコープ内のどこからでもその変数にアクセスできます。

59
jAndy

来年、すべてのブラウザにコードをプリコンパイルするJSエンジンが搭載されるため、パフォーマンスの違い(同じコードブロックを何度も解析し、割り当てを実行することによる)は無視できるようになります。

また、必要がない限り、パフォーマンスを最適化しないでください。変数を最初に必要な場所に近づけておくと、コードがきれいになります。マイナス面として、ブロックスコープを持つ言語に慣れている人は混乱するかもしれません。

13
Aaron Digulla

Chromeで簡単なテストを行いました。ブラウザで fiddle を試して結果を確認します

  var count = 100000000;
    var a = 0;
    console.log(new Date());

    for (var i=0; i<count; i++) {
      a = a + 1
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
      a = a + 1;
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
        var x;
        x = x + 1;
    }

    console.log(new Date());

結果は、最後のテストに最大8秒かかり、前の2つは最大2秒です。順序に関係なく、非常に繰り返し可能です。

したがって、これは、ループの外側で常に変数を宣言する必要があることを証明しています。好奇心が強いのは、for()ステートメントでiを宣言する最初のケースです。これは、インデックスを事前に宣言する2番目のテストと同じくらい速いようです。

4
mkoistinen

もう1つの考慮事項は、ES2015でletconstが用意されたため、変数をループブロック専用にスコープできることです。したがって、ループの外側で同じ変数が必要でない限り(または、各反復が前の反復でその変数に対して行われた操作に依存する場合)、おそらくこれを行うのが望ましいでしょう:

for (let i = 0; i < 100; i++) {
    let value = somearray[i];
    //do something with `value`
}
3
Matt Browne

JavaScriptはCまたはC++によって下部に記述された言語であり、どちらの言語かはよくわかりません。また、その目的の1つは、内部メモリを処理する方法を節約することです。 CまたはC++でも、変数がループ内で宣言されたときに大量のリソースを消費するかどうかを心配する必要はありません。 JavaScriptでそれを心配する必要があるのはなぜですか?

1
Yan Yang

まあ、それはあなたが達成しようとしているものに依存します... valueがループブロック内の一時変数のみであると仮定した場合、2番目の形式を使用する方がはるかに明確です。また、より論理的で冗長です。

0
Crozin

Forループの内側または外側で変数を宣言しても違いはありません。以下はテストするサンプルコードです。

function a() {
   console.log('Function a() starts');
   console.log(new Date());
    var j;
    for (j=0; j<100000000; j++) {
        var x;
        x = x + 1;
    }
    console.log(new Date());
    console.log('Function a() Ends');
}
a()
function b() {
console.log('Function B() starts');
   console.log(new Date());
    var a;
    var j;
    for (j=0; j<100000000; j++) {
      a = a + 1;
    }
    console.log(new Date());
    console.log('Function B() Ends');
}
b()

結果は私の場合に示した

Function a() starts
VM121:3 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:9 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:10 Function a() Ends
VM121:14 Function B() starts
VM121:15 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:21 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:22 Function B() Ends

ありがとう-MyFavs.in

0
myfavs.in