web-dev-qa-db-ja.com

JSLintエラー「for inの本体はifステートメントでラップする必要があります」とはどういう意味ですか?

私のJavaScriptファイルで JSLint を使用しました。エラーを投げました:

for( ind in evtListeners ) {

41行目9文字の問題:for inの本体をifステートメントでラップして、プロトタイプから不要なプロパティをフィルタリングする必要があります。

これは何を意味するのでしょうか?

231
jrharshath

まず、neverfor inループを使用して配列を列挙します。決して。古き良きfor(var i = 0; i<arr.length; i++)を使用してください。

この理由は次のとおりです。JavaScriptの各オブジェクトには、prototypeという特別なフィールドがあります。そのフィールドに追加するものはすべて、そのタイプのすべてのオブジェクトでアクセス可能になります。すべての配列に、ゼロを除去するfilter_0というクールな新しい関数を追加するとします。

Array.prototype.filter_0 = function() {
    var res = [];
    for (var i = 0; i < this.length; i++) {
        if (this[i] != 0) {
            res.Push(this[i]);
        }
    }
    return res;
};

console.log([0, 5, 0, 3, 0, 1, 0].filter_0());
//prints [5,3,1]

これは、オブジェクトを拡張し、新しいメソッドを追加する標準的な方法です。多くのライブラリがこれを行います。ただし、for inがどのように機能するかを見てみましょう。

var listeners = ["a", "b", "c"];
for (o in listeners) {
    console.log(o);
}
//prints:
//  0
//  1
//  2
//  filter_0

見える?突然filter_0は別の配列インデックスであると考えられます。もちろん、実際には数値インデックスではありませんが、for inは数値インデックスだけでなく、オブジェクトフィールドを列挙します。そのため、すべての数値インデックスandfilter_0を列挙しています。ただし、filter_0は特定の配列オブジェクトのフィールドではなく、すべての配列オブジェクトにこのプロパティがあります。

幸いなことに、すべてのオブジェクトにはhasOwnPropertyメソッドがあり、このフィールドが実際にオブジェクト自体に属しているか、プロトタイプチェーンから単純に継承され、そのタイプのすべてのオブジェクトに属しているかをチェックします。

for (o in listeners) {
    if (listeners.hasOwnProperty(o)) {
       console.log(o);
    }
}
 //prints:
 //  0
 //  1
 //  2

このコードは配列に対して期待どおりに動作しますが、決してneverにしてはいけません。配列にはfor infor each inを使用してください。 for inは配列のインデックスや値ではなく、オブジェクトのフィールドを列挙することに注意してください。

var listeners = ["a", "b", "c"];
listeners.happy = "Happy debugging";

for (o in listeners) {
    if (listeners.hasOwnProperty(o)) {
       console.log(o);
    }
}

 //prints:
 //  0
 //  1
 //  2
 //  happy
411
vava

Jslintの著者であるDouglas Crockfordは、この問題について何度も書いています(そして話しています)。彼のウェブサイトの this ページにこれをカバーするセクションがあります:

for Statement

Forクラスのステートメントの形式は次のとおりです。

for (initialization; condition; update) {
    statements
}

for (variable in object) {
    if (filter) {
        statements
    } 
}

最初の形式は、配列および繰り返し回数が事前に決定可能なループで使用する必要があります。

2番目の形式はオブジェクトで使用する必要があります。オブジェクトのプロトタイプに追加されたメンバーが列挙に含まれることに注意してください。 hasOwnPropertyメソッドを使用してオブジェクトの真のメンバーを区別することにより、防御的にプログラムすることが賢明です。

for (variable in object) {
    if (object.hasOwnProperty(variable)) {
        statements
    } 
}

CrockfordにはYUIシアターに関するビデオシリーズもあり、そこで彼はこれについて語っています。 javascriptについてのCrockfordのビデオ/トークのシリーズは、javascriptについて少しでも真剣に取り組んでいるかどうかを確認する必要があります。

86
Breton

悪い:(jsHintはエラーをスローします)

for (var name in item) {
    console.log(item[name]);
}

良い:

for (var name in item) {
  if (item.hasOwnProperty(name)) {
    console.log(item[name]);
  }
}
17
wangchi

Vavaの答えは順調です。 jQueryを使用する場合、$.each()関数がこれを処理するため、使用する方が安全です。

$.each(evtListeners, function(index, elem) {
    // your code
});
9
HRJ

@all-JavaScriptのすべてはオブジェクト()であるため、「これをオブジェクトでのみ使用する」などのステートメントは誤解を招く可能性があります。さらに、JavaScriptは厳密に型指定されていないため、1 == "1"が真になります(1 === "1"はそうではありませんが、Crockfordはこの点で大きくなっています)。 JSの配列のプログロマティックな概念になると、定義ではタイピングが重要になります。

@Brenton-用語の独裁者である必要はありません。 「連想配列」、「辞書」、「ハッシュ」、「オブジェクト」、これらのプログラミング概念はすべて、JSの1つの構造に適用されます。名前(キー、インデックス)値のペアです。値は他のオブジェクトにすることができます(文字列もオブジェクトです)

したがって、new Array()[]と同じです

new Object(){}とほぼ同じです

var myarray = [];

すべてのインデックス(別名キー)は整数でなければならないという制限のある配列である構造を作成します。また、.Push()を介して新しいインデックスの自動割り当てを可能にします

var myarray = ["one","two","three"];

for(initialization;condition;update){を介して本当に対処するのが最善です

しかし、どうですか:

var myarray = [];
myarray[100] = "foo";
myarray.Push("bar");

これを試して:

var myarray = [], i;
myarray[100] = "foo";
myarray.Push("bar");
myarray[150] = "baz";
myarray.Push("qux");
alert(myarray.length);
for(i in myarray){
    if(myarray.hasOwnProperty(i)){  
        alert(i+" : "+myarray[i]);
    }
}

おそらく、アレイの最適な使用法ではなく、物事が常に明確であるとは限らないという実例です。

キーを知っていて、それらが整数でない場合は間違いなく、構造オプションのような唯一の配列はオブジェクトです。

var i, myarray= {
   "first":"john",
   "last":"doe",
   100:"foo",
   150:"baz"
};
for(i in myarray){
    if(myarray.hasOwnProperty(i)){  
        alert(i+" : "+myarray[i]);
    }
}
7
wade

言うことは確かに少し極端です

... for inループを使用して配列を列挙しないでください。決して。古き良きfor(var i = 0; i <arr.length; i ++)を使用する

ダグラス・クロックフォード抽出物のセクションを強調する価値があります

... 2番目のフォームはオブジェクトで使用する必要があります...

キーが数値インデックスではなく名前が付けられている連想配列(別名hashtable/dictionary)が必要な場合は、これをオブジェクトとして実装する必要があります。 var myAssocArray = {key1: "value1", key2: "value2"...};

この場合、myAssocArray.lengthはnullになり(このオブジェクトには 'length'プロパティがないため)、i < myAssocArray.lengthはあまり遠くに行きません。配列キーは有用なプロパティ(配列メンバーのIDプロパティまたは名前)である可能性があるため、連想配列は多くの状況でパフォーマンス上の利点を提供することが期待されます。 ifステートメントを繰り返し評価して、目的の配列エントリを見つけます。

とにかく、JSLintエラーメッセージの説明にも感謝します。無数の連想配列を操作するときに、「isOwnProperty」チェックを使用します。

2
tomfumb

これは、evtListenersのプロパティを hasOwnPropertyメソッド でフィルタリングする必要があることを意味します。

0
Fabien Ménager

For/for/$。eachのトピックに追加するために、$。each対forを使用するためのjsperfテストケースを追加しました。 http://jsperf.com/each-vs-for- in/2

ブラウザー/バージョンによって処理方法が異なりますが、パフォーマンス面では、それぞれが$ .eachで最も安価なオプションです。

For inを使用して連想配列/オブジェクトを反復処理し、目的を理解し、他のすべてを無視する場合、jQueryを使用する場合は$ .eachを使用するか、またはin(およびbreak)を使用します。最後の要素であることがわかっているものに到達した)

配列を反復処理して各キーペアで何かを実行する場合、jQueryを使用しない場合はhasOwnPropertyメソッドを使用し、jQueryを使用する場合は$ .eachを使用する必要があります。

連想配列が必要ない場合は、常にfor(i=0;i<o.length;i++)を使用してください... lol chromeは、for inや$.eachよりも97%高速に実行しました

0
Benno