JSHintを使用してJavaScriptコードをリントしていました。コードには、次のように使用される2つのforループがあります。
for (var i = 0; i < somevalue; i++) { ... }
したがって、両方のforループは反復にvar iを使用します。
これで、JSHintは2番目のforループのエラーを表示します:「 'i' is already defined」。私はこれが本当ではないと言うことはできません(明らかにそうです)が、var iはその特定の場所でのみ使用されるため、これは重要ではないと常に思っていました。
このようにforループを使用するのは悪い習慣ですか?私のコードのforループごとに異なる変数を使用する必要があります
//for-loop 1
for (var i = 0; ...; i++) { ... }
//for-loop 2
for (var j = 0; ...; j++) { ... }
または、これは私が無視できるエラーの1つです(それは私のコードを壊さないので、それはまだそれがするはずのことをします)?
JSLint btw。関数の先頭で変数iを定義していないため、最初のforループで検証が停止します(そのため、最初にJSHintに切り替えました)。したがって、この質問の例によると、 JSLintまたはJSHint JavaScript検証を使用する必要がありますか? – JSLintを確認するには、とにかくこのようなforループを使用する必要があります。
...
var i;
...
//for-loop 1
for (i = 0; ...; i++) { ... }
...
//for-loop 2
for (i = 0; ...; i++) { ... }
JSLintとJSHintの両方のエラーを回避する必要があるため、これも私には良さそうです。しかし、次のようにforループごとに異なる変数を使用する必要があるかどうかについて、私は不確かです。
...
var i, j;
...
//for-loop 1
for (i = 0; ...; i++) { ... }
//for-loop 2
for (j = 0; ...; j++) { ... }
だから、これにはベストプラクティスがありますか、上記のコードのいずれかで行くことができますか?つまり、「私の」ベストプラクティスを選択しますか?
変数宣言は、それらが現れるスコープの最上部に引き上げられるため、インタープリターは両方のバージョンを同じ方法で効果的に解釈します。そのため、JSHintとJSLintは、ループ初期化子から宣言を移動することをお勧めします。
次のコード...
for (var i = 0; i < 10; i++) {}
for (var i = 5; i < 15; i++) {}
...は次のように効果的に解釈されます。
var i;
for (i = 0; i < 10; i++) {}
for (i = 5; i < 15; i++) {}
i
の宣言は実際には1つしかなく、複数の割り当てがあることに注意してください。同じスコープ内で変数を「再宣言」することはできません。
実際に質問に答えるには...
これにはベストプラクティスがありますか、上記のコードのいずれかを使用できますか?
これをどのように処理するのが最適かについては、さまざまな意見があります。個人的には、JSLintに同意し、各スコープの上部ですべての変数を一緒に宣言すると、コードがより明確になると思います。それがコードの解釈方法なので、動作するように見えるコードを書いてみませんか?
しかし、あなたが観察したように、コードは採用されたアプローチに関係なく機能するため、スタイル/慣習の選択であり、あなたが最も快適だと思う形式を使用できます。
JavaScriptの変数は関数スコープです(ブロックスコープではありません)。
var i
をループで定義すると、ループ内およびそのループを持つ関数内に残ります。
下記参照、
function myfun() {
//for-loop 1
for (var i = 0; ...; i++) { ... }
// i is already defined, its scope is visible outside of the loop1.
// so you should do something like this in second loop.
for (i = 0; ...; j++) { ... }
// But doing such will be inappropriate, as you will need to remember
// if `i` has been defined already or not. If not, the `i` would be global variable.
}
@ TSCrowderによるコメント でのみ言及されています:環境でサポートされている場合(Firefox、Node.js)、ES6では let
宣言 を使用できます=
//for-loop 1
for (let i = 0; ...; i++) { ... }
//for-loop 2
for (let i = 0; ...; i++) { ... }
whichは、for-loop内にスコープを制限します。ボーナス:JSHintは文句を言いません。
JSHintがエラーを表示する理由は、JS変数スコープは関数であり、変数宣言は関数の最上部に引き上げられているためです。
Firefoxでは、let
キーワードを使用してブロックスコープを定義できますが、現在他のブラウザーではサポートされていません。
let
キーワードはECMAScript 6仕様に含まれています。
私はこの質問に回答したことを知っていますが、スーパーforループが必要な場合は、次のように記述してください。
var names = ['alex','john','paul','nemo'],
name = '',
idx = 0,
len = names.length;
for(;idx<len;++idx)
{
name = names[idx];
// do processing...
}
ここで起こっているいくつかのこと...
配列の長さはlen
に保存されています。これにより、JSがnames.length
を繰り返すたびに評価しなくなります
idx
増分はプリインクリメントです(例:++ idx NOT idx ++)。プレインクリメントは、ポストインクリメントよりもネイティブに高速です。
name
への参照の保存。これはオプションですが、name
変数を頻繁に使用する場合に推奨されます。 names[idx]
を呼び出すたびに、配列内のインデックスを見つける必要があります。この検索が線形検索、ツリー検索、ハッシュテーブルのいずれであっても、検索は行われています。したがって、参照を減らすために別の変数に参照を保存します。
最後に、これは私の個人的な好みであり、証拠もパフォーマンス上の利点もありません。ただし、変数を初期化するタイプは常に好きです。 name = '',
。
ベストプラクティスは変数のスコープを減らすことです。そのため、ループの反復変数を宣言する最良の方法は
//for-loop 1
for (var i = 0; ...; i++) { ... }
//for-loop 2
for (var j = 0; ...; j++) { ... }
var
で宣言された変数のスコープは知っていますが、ここではコードを読みやすくしています。