web-dev-qa-db-ja.com

ループ変数の重複宣言警告の処理

次のコードを検討してください。

for (var i=0; i<100; i++) {
    // your code here
}
// some other code here
for (var i=0; i<500; i++) {
    // custom code here
}

まともなlintツール(jslint、jshint、または組み込みIDE)は警告を通知します-duplicate declaration of variable i。これは、別の名前の変数(kj)を使用するか、宣言を先頭に移動することで解決できます。

var i; // iterator
for (i=0; i<100; i++) {}
for (i=0; i<500; i++) {}

私は両方のバリアントが好きではありません-通常、最初に宣言を行いません(そして、たとえそうしたとしても、ヘルパー変数を表示したくありません-ijk)そして、変数の名前を変更するこれらの例では、本当に悪いことは何も起こっていません。

私がこのようなものを書いた場合に備えて、私は大きな警告が必要ですが:

for (var i=0; i<100; i++) {
    for (var i=0; i<500; i++) {} // now that's bad
}

そのような場合のあなたのアプローチは何ですか?

47
Ilya Tsuryev

JavaScriptには、他のコンピューター言語でよく知られている構造のように見える多くの構造があります。 JavaScriptが他のほとんどのコンピューター言語と同じように another で構文を解釈するのは危険です。

JavaScriptを十分に理解していない人(ちなみに一般的なケース)が次のような構成を見た場合

for (var i=0; i<100; i++) {
    // your code here
}

またはブロック内の変数の宣言を見ます

{
    var i;
    //some code
    {
        var j;
        // some code
    }
}

その場合、ほとんどの読者は、ブロックレベルの変数が定義されると考えます。 JavaScriptにはブロックレベルの変数はありません。すべての変数は、定義された関数レベルとして解釈されます。

したがって、コードが5分間だけ書かれるテストコードだけではない場合、コード内の変数を定義しないでください。主な理由は誤解される可能性のあるコードを記述したり、言語構造を使用したりしたくないです。

ちなみにJSLintは、ブロック内の変数の定義を見つけて、コード分析の処理を停止するような悪いスタイルを見つけます。この動作を変更する可能性のあるJSLintオプションはありません。 JSLintの動作は良くないと思いますが、forループ内の変数の宣言は local ループ変数。これは正しくありません。

使用する場合

for (var i=0; i<100; i++) {
    // your code here
}
// some other code here
for (var i=0; i<500; i++) {
    // custom code here
}

次に、JavaScriptが変数のすべての宣言を function の先頭に移動します。したがって、コードは次のようになります

var i = undefined, i = undefined; // duplicate declaration which will be reduced
                                  // to one var i = undefined;

for (i=0; i<100; i++) {
    // your code here
}
// some other code here
for (i=0; i<500; i++) {
    // custom code here
}

したがって、コードの他の読者について考えてください。間違って解釈される可能性のある構文を使用しないでください。

48
Oleg

letキーワードは、JavaScript 1.7で導入されました。 MDNのドキュメントをご覧ください こちら

varletに置き換えfor loopは問題を解決し、ループのスコープ内でローカル変数を宣言できるようになりました。ここでstackoverlowコミュニティの説明を確認してください: 変数の宣言に「let」と「var」を使用することの違いは何ですか?

今後のコード:

for (let i = 0; i < someVar.length; i++) {
    // do your thing here
}
18
Said Kholov

ループが何をしているかを示す名前を持つ自己実行関数でループを囲むことをお勧めします。これにより、ループにブロックスコープが効果的に与えられます。例えば:

_var users = response['users']
;(function appendUsers(){
    for (var i = 0; i < users.length; i++) {
        var user      = users[i]
        var userEmail = user['email']
        var userId    = user['id']
        /* etc */ 
    }
})() // appendUsers
_

これを行う場合:

_var i
for (i = 0; i < someVar.length; i++) {
    for (i = 0; i < someOtherVar.length; i++) {
        // This is a bug that a validator will not notice.
    }
}
_

一方:

_for (var i = 0; i < someVar.length; i++) {
    for (var i = 0; i < someOtherVar.length; i++) {
        // This is a bug that a validator will warn you about.
    }
}
for (var i = 0; i < yetAnotherVar.length; i++) {
    // It will also warn you about this, but so what?
}
_

イテレータとしてのiの使用を停止できます。

_for (var companyIndex = 0; companyIndex < companies.length; companyIndex++) {
    var company = companies[companyIndex]
}
_

とにかくjQueryを使用している場合は、その jQuery.each() メソッドを使用できます。

_$.each(someVar, function(i, value){
    // etc
})
_

Polyfill code などを追加しない限り、IE8以前を機能させる場合は Array.prototype.forEach() を使用できません。

6
Vladimir Kornea

Map、filter、forEachなどの配列組み込み関数を使用する傾向があるため、この問題は完全に回避されます。これにより、スコープループ本体も自動的に提供されます。これも非常に便利です。

それらを使用することがユースケースと一致しない場合、私は通常トップ宣言に頼るので、単にあなたが言及した問題を回避することができます。

2
Exelian

ここでのベストプラクティスは、優れたプログラミングスタイルである必要があります。

プログラムは短い関数で構成する必要があり、1つの小さなタスクを実行します。通常、ループしている場合は、独自の関数に立つような特別なことを行います。結局、すべての関数には独自のスコープがあるため、重複した宣言の問題はなくなります。

function myApp() {
    magicLoopAction();
    someOtherMagicStuff();
}
function magicLoopAction() {
    for (var i = 0; i < 42; i++) { 
        // whoopwhoop
    }
}
function someOtherMagicStuff() {
    for (var i = 0; i < 69; i++) { 
        // lint is happy and proud on you
    }
}
1
Putzi San