63

JSHint を使用して JavaScript コードを lint していました。コードには、次のように使用される 2 つの for ループがあります。

for (var i = 0; i < somevalue; i++) { ... }

したがって、両方の for ループは反復に var i を使用します。

ここで、JSHint は 2 番目の for ループのエラーを表示します:「'i' は既に定義されています」。これが真実ではないとは言えませんが(明らかにそうであるため)、var i はその特定の場所でのみ使用されるため、これは問題ではないと常に考えていました。

このように for ループを使用するのは悪い習慣ですか? 次のように、コード内の for ループごとに異なる変数を使用する必要がありますか?

//for-loop 1
for (var i = 0; ...; i++) { ... }

//for-loop 2
for (var j = 0; ...; j++) { ... }

それとも、これは無視できるエラーの 1 つですか (コードが壊れないため、本来の動作を実行します)。

JSLintところで。関数の先頭で var 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++) { ... }

これにはベストプラクティスがありますか、それとも上記のコードのいずれかを使用できますか?つまり、「私の」ベストプラクティスを選択できますか?

4

6 に答える 6

60

変数宣言はそれらが表示されるスコープの先頭に引き上げられるため、インタープリターは両方のバージョンを同じ方法で効果的に解釈します。そのため、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++) {}

の宣言は 1 つだけでi、複数の代入があることに注意してください。実際には、同じスコープ内で変数を「再宣言」することはできません。

実際にあなたの質問に答えるには...

これにはベストプラクティスがありますか、それとも上記のコードのいずれかを使用できますか?

これをどのように処理するのが最善かについては、さまざまな意見があります。個人的には、JSLint に同意します。各スコープの先頭ですべての変数をまとめて宣言すると、コードがより明確になると思います。コードはそのように解釈されるので、実際に動作するように見えるコードを作成してみませんか?

しかし、ご覧のとおり、コードはどのアプローチを採用しても機能するため、スタイル/規則の選択であり、最も使いやすい形式を使用できます。

于 2013-04-03T09:11:27.803 に答える
7

@TSCrowder のコメントでのみ言及されています。環境がサポートしている場合 (Firefox、Node.js)、ES6 では宣言を使用できます。let

//for-loop 1
for (let i = 0; ...; i++) { ... }

//for-loop 2
for (let i = 0; ...; i++) { ... }

スコープを for-loop 内に制限します。おまけ: JSHint は不平を言うのをやめます。

于 2016-04-04T07:20:16.113 に答える
6

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.
}
于 2013-04-03T09:12:56.170 に答える
4

JSHint がエラーを表示する理由は、JS では変数のスコープが関数であり、変数宣言が関数の先頭に引き上げられるためです。

Firefox では、letキーワードを使用してブロック スコープを定義できますが、現在、他のブラウザーではサポートされていません。

letキーワードは ECMAScript 6 仕様に含まれています。

于 2013-04-03T09:12:50.743 に答える
4

この質問には回答済みですが、スーパー for ループが必要な場合は、次のように記述します。

var names = ['alex','john','paul','nemo'],
    name = '',
    idx = 0,
    len = names.length;

for(;idx<len;++idx)
{
    name = names[idx];
    // do processing...
}

ここでいくつかのことが起こっています...

  1. 配列の長さは に格納されていlenます。これにより、JSnames.lengthはすべての反復を評価しなくなります

  2. インクリメントはidxPRE-INCREMENT です (例: ++idx NOT idx++)。プリインクリメントは、ポストインクリメントよりもネイティブに高速です。

  3. への参照の格納namenameこれはオプションですが、変数を頻繁に使用する場合はお勧めします。を呼び出すたびnames[idx]に、配列内のインデックスを見つける必要があります。この検索が線形検索、ツリー検索、またはハッシュ テーブルのいずれであっても、検索は引き続き行われます。そのため、参照を別の変数に格納して、ルックアップを減らします。

最後に、これは私の個人的な好みに過ぎず、証明もパフォーマンス上の利点もありません。ただし、私は常に、変数を次のような型に初期化するのが好きですname = '',

于 2013-11-19T11:28:22.737 に答える
1

ベスト プラクティスは、変数のスコープを縮小することです。そのため、ループの反復変数を宣言する最良の方法は次のとおりです。

//for-loop 1
for (var i = 0; ...; i++) { ... }

//for-loop 2
for (var j = 0; ...; j++) { ... }

で宣言された変数のスコープは知っていますが、varここではコードの読みやすさについて考えています。

于 2013-04-03T09:11:11.117 に答える