15

Javascript で奇妙な動作に直面しました。私は得る

「オブジェクトはこのプロパティまたはメソッドをサポートしていません」

removeAttribute次のコードの関数の例外:

var buttons = controlDiv.getElementsByTagName("button");
for ( var button in buttons )
    button.removeAttribute('disabled');

次のようにコードを変更すると、問題はなくなります。

var buttons = controlDiv.getElementsByTagName("button");
for ( var i = 0; i < buttons.length; i++ )
    buttons[i].removeAttribute('disabled');

buttonの内部の値は何for...inですか?

4

4 に答える 4

48

for..in配列反復には使用しないでください。

[]インデックスにアクセスするための Javascript 配列の角括弧構文 ( ) は、実際にはObject...から継承されていることを理解することが重要です。

obj.prop === obj['prop']  // true

この構造は、他の言語 (php、python など) に見られるfor..inより伝統的な構造とは異なります。for..each/in

Javascriptは、オブジェクトfor..inのプロパティを反復処理するように設計されています。各プロパティのキーを生成します。このキーを 's ブラケット構文と組み合わせて使用​​すると、目的の値に簡単にアクセスできます。Object

var obj = {
    foo: "bar",
    fizz: "buzz",
    moo: "muck"
};

for ( var prop in obj ) {
    console.log(prop);      // foo / fizz / moo
    console.log(obj[prop]); // bar / buzz / muck
}

また、Array は、連続する数値プロパティ名 (インデックス)を持つ単なるオブジェクトであるため、同様の方法でfor..in機能し、上記のプロパティ名を生成するのと同じように数値インデックスを生成します。

構造体の重要な特徴はfor..in、プロトタイプ チェーンを上って列挙可能なプロパティを検索し続けることです。また、継承された列挙可能なプロパティを反復します。現在のプロパティがローカル オブジェクトに直接存在し、それが関連付けられているプロトタイプに存在しないことを確認するのはあなた次第ですhasOwnProperty()...

for ( var prop in obj ) {
    if ( obj.hasOwnProperty(prop) ) {
        // prop is actually obj's property (not inherited)
    }
}

(プロトタイプ継承の詳細)

Array 型で構造体を使用する際の問題はfor..in、プロパティが生成される順序について保証がないことです...そして一般的に言えば、それは配列を処理する上で非常に重要な機能です。

もう 1 つの問題は、通常、標準の実装よりも遅いことです。for

結論

配列を反復処理するためにa を使用するfor...inことは、ドライバーのバットを使用して釘を打ち込むようなものです...ハンマー ( for) を使用しないのはなぜですか?

于 2011-03-10T18:11:18.870 に答える
7

for...inオブジェクトのプロパティをループしたい場合に使用します。ただし、通常のループと同じように機能しforます。ループ変数には、値ではなくオブジェクトのプロパティを意味する現在の「インデックス」が含まれます。

配列を反復するには、通常のforループを使用する必要があります。buttonsは配列ではなくNodeList(配列のような構造) です。

buttonsで繰り返す場合for...in

for(var i in a) {
    console.log(i)
}

次のような出力が表示されます。

1
2
...
length
item

lengthitemは 型のオブジェクトの 2 つのプロパティであるためNodeListです。したがって、単純に を使用する場合は、関数であり DOM 要素ではないため、エラーをスローするfor..inにアクセスしようとします。buttons['length'].removeAttribute()buttons['length']

したがって、正しい方法は通常のforループを使用することです。しかし、別の問題があります。

NodeListはライブです。つまり、アクセスするたびlengthに、リストが更新されます (要素が再度検索されます)。したがって、不要な への呼び出しは避ける必要がありますlength

例:

for(var i = 0, l = buttons.length; i < l, i++)
于 2011-03-10T18:17:29.323 に答える
0

for(var key in obj) { }プロトタイプの要素を含む、オブジェクト内のすべての要素を反復処理します。したがって、それを使用していて拡張されたものが何もわからないObject.prototype場合は、常にテストobj.hasOwnProperty(key)して、このチェックが false を返す場合はキーをスキップする必要があります。

for(start; continuation; loop)は C スタイルのループです: ループstartの前に実行され、continuationテストされ、ループは true の間のみ継続し、loopすべてのループの後に実行されます。

于 2011-03-10T18:13:44.230 に答える
0

for..in は通常、配列に使用するべきではありませんが、ES5 より前では、スパース配列で使用する場合がありました。

他の回答で述べたように、 for..in と配列の主な問題は次のとおりです。

  1. プロパティは必ずしも順番に返されるとは限りません (つまり、0、1、2 などではありません)。
  2. [[Prototype]]インデックス以外のプロパティやチェーン上のプロパティを含め、すべての列挙可能なプロパティが返されます。これは、継承されたプロパティを回避するためにおそらくhasOwnPropertyテストが必要になるため、パフォーマンスの低下につながります。

ES5 より前に for..in を使用する理由の 1 つは、順序が問題にならない場合に、スパース配列でパフォーマンスを向上させることでした。たとえば、次のようになります。

var a = [0];
a[1000] = 1;

for..in を使用して反復処理を行うと、for ループを使用するよりもはるかに高速になります。これは、for ループが 1001 を試行するのに対し、2 つのプロパティのみを参照するためです。

ただし、このケースは、存在するメンバーのみを訪問する ES5 のforEachによって冗長になります。

a.forEach();

また、2 つのプロパティを順番に繰り返すだけです。

于 2014-10-08T05:08:51.477 に答える