私のJavaScriptファイルでJSLintを使用しました。それはエラーを投げました:
for( ind in evtListeners ) {
41行目の問題9文字目:プロトタイプから不要なプロパティをフィルター処理するには、forステートメントの本文をifステートメントでラップする必要があります。
これは何を意味するのでしょうか?
私のJavaScriptファイルでJSLintを使用しました。それはエラーを投げました:
for( ind in evtListeners ) {
41行目の問題9文字目:プロトタイプから不要なプロパティをフィルター処理するには、forステートメントの本文をifステートメントでラップする必要があります。
これは何を意味するのでしょうか?
回答:
まず、ループを使用して配列を列挙しないでfor 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
だけでなく、オブジェクトフィールド全体を列挙します。したがって、すべての数値インデックスとを 列挙しますfilter_0
。しかしfilter_0
、特定の配列オブジェクトのフィールドではなく、すべての配列オブジェクトがこのプロパティを持っています。
幸いなことに、すべてのオブジェクトにはhasOwnProperty
メソッドがあり、このフィールドが実際にオブジェクト自体に属しているか、それともプロトタイプチェーンから単に継承され、そのタイプのすべてのオブジェクトに属しているかをチェックします。
for (o in listeners) {
if (listeners.hasOwnProperty(o)) {
console.log(o);
}
}
//prints:
// 0
// 1
// 2
このコードは配列に対しては期待どおりに動作しますが、配列に対しては絶対に使用for in
しないでくださいfor 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
for in
言語はfor in
配列を列挙する順序を保証しないため、配列の反復には使用しないでください。番号順ではない可能性があります。さらに、 `for(i = 0; i <array.length; i ++)スタイルコンストラクトを使用する場合、英数字のプロパティではなく、順番に数値インデックスのみを反復していることを確認できます。
for-in
ループから人々を怖がらせるのではなく(すごいですが)、ループがどのように機能するかを教育し(この回答では正しく行われます)、Object.defineProperty()
何も壊さずにプロトタイプを安全に拡張できるように紹介する必要があると思います。ちなみに、ネイティブオブジェクトのプロトタイプの拡張は、なしで行うべきではありませんObject.defineProperty
。
jslintの作者であるDouglas Crockfordは、この問題について何度も書いています(そして話しました)。これをカバーする彼のウェブサイトのこのページにセクションがあります:
ステートメント用
ステートメントのクラスは次の形式にする必要があります。
for (initialization; condition; update) { statements } for (variable in object) { if (filter) { statements } }
最初の形式は、配列および事前に決定可能な反復回数のループで使用する必要があります。
2番目のフォームはオブジェクトで使用する必要があります。オブジェクトのプロトタイプに追加されたメンバーは列挙に含まれることに注意してください。オブジェクトの実際のメンバーを区別するためにhasOwnPropertyメソッドを使用して防御的にプログラムするのが賢明です。
for (variable in object) { if (object.hasOwnProperty(variable)) { statements } }
また、クロックフォードはYUIシアターで彼がこれについて語るビデオシリーズを持っています。JavaScriptに関するCrockfordの一連のビデオ/講演は、JavaScriptについて少しでも真剣であるかどうかを確認する必要があります。
ヴァヴァの答えが目印です。jQueryを使用する場合、$.each()
関数がこれを処理するため、使用する方が安全です。
$.each(evtListeners, function(index, elem) {
// your code
});
@all-JavaScriptのすべてがオブジェクト()であるため、「オブジェクトでのみ使用」などのステートメントは少し誤解を招きます。さらに、JavaScriptは強く型付けされていないため、1 == "1"はtrueです(1 === "1"はそうではありませんが、Crockfordはこれに大きく関わっています)。JSでの配列のprogromatic概念に関して言えば、定義では型付けが重要です。
@ブレントン-専門用語専門家である必要はありません。「連想配列」、「辞書」、「ハッシュ」、「オブジェクト」、これらのプログラミング概念はすべて、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]);
}
}
きっと言うのは少し極端です
...配列を列挙するためにfor inループを使用しないでください。決して。古き良きものを使用(var i = 0; i <arr.length; i ++)
?
ダグラス・クロックフォード抽出物のセクションを強調表示する価値があります
... 2番目のフォームはオブジェクトで使用する必要があります...
数値インデックスの代わりにキーに名前が付けられている連想配列(別名ハッシュテーブル/ディクショナリ)が必要な場合は、これをオブジェクトとして実装する必要がありますvar myAssocArray = {key1: "value1", key2: "value2"...};
。
この場合myAssocArray.length
、nullが表示され(このオブジェクトには「length」プロパティi < myAssocArray.length
がないため)、それほど遠くまで到達できません。配列キーは便利なプロパティ(つまり、配列メンバーのIDプロパティまたは名前)となるため、連想配列は多くの状況でパフォーマンス上の利点を提供することを期待しています。配列は、ifステートメントを繰り返し評価して、目的の配列エントリを見つけます。
とにかく、JSLintエラーメッセージの説明にも感謝します。無数の連想配列を処理するときは、「isOwnProperty」チェックを使用します。
length
財産を、しかし、あなたはそれを別の方法を行うことができます:var myArr = []; myArr['key1'] = 'hello'; myArr['key2'] = 'world';
var myArr = []
、を使用しないでください。PHPではvar myArr = {}
同じですが、JSでは使用できません。
つまり、hasOwnPropertyメソッドでevtListenersのプロパティをフィルタリングする必要があります。
ちょうどのために/ $各/中についての話題に追加するために、私は中のために対$ .eachを使用するためのjsperfテストケースを追加しました:http://jsperf.com/each-vs-for-in/2
ブラウザー/バージョンによって処理方法は異なりますが、$。eachとストレートフォーインはパフォーマンス面で最も安価なオプションのようです。
for inを使用して連想配列/オブジェクトを反復処理し、目的を把握して他のすべてを無視している場合は、jQueryを使用する場合は$ .eachを使用するか、単にfor(そして改行)を使用します最後の要素であるべきことがわかっているものに到達した)
配列を反復処理して、その中の各キーペアで何かを実行する場合、jQueryを使用しない場合はhasOwnPropertyメソッドを使用し、jQueryを使用する場合は$ .eachを使用する必要があります。
for(i=0;i<o.length;i++)
ただし、連想配列が必要ない場合は、常に使用してください... lol chromeは、for inまたは$.each
if (evtListeners.hasOwnProperty(ind))
、処理を所有する(継承されない)プロパティのみに制限します。それでも、継承されたプロパティを含むすべてのプロパティを本当に反復処理したい場合があります。その場合、JSLintは、ループ本体をifステートメントでラップして、本当に必要なプロパティを決定するように強制します。これは、仕事とJSlintの幸せになる:if (evtListeners[ind] !== undefined)