2017-01-08 9 views
2

CrockfordのThe Good Partsの本は、JavaScript配列が実際にオブジェクトであることを伝えています。オブジェクトごとに呼び出す

これを考えると、なぜこれは機能しませんか? (そして、それを期待ため、私は奇妙なのですか?)

arr={0:'a', 1:'b', 2:'c', 3:'d'} 

Array.prototype.forEach.call(arr, function(el){console.log(el)}) 

私の思考:配列は、おそらく、キーの昇順で配列のプロパティを通じてforEachループのようなメソッドオブジェクトである場合。 (そして、callを通して、メソッドが動作するthisを設定することができます)。私はそれが[].forEach.call(NodeList)の理由であると仮定しています。

+7

あなたは 'length'プロパティを忘れました。 'length:4' https://jsfiddle.net/19to1oy6/ –

+0

@squintああ、私は' arr.length = 4'でした。ありがとう! –

+0

ようこそ。 –

答えて

3

問題は、オブジェクトにlengthという文字がないことです。.forEach()どのくらい反復するか。

これは重要です。なぜなら、JS配列はスパースである可能性があるため、単に終了する必要があるかどうかを判断するプロパティの存在を確認するだけではなく、次のインデックスに値。

長さが正しく設定されていないと、最初の比較では繰り返しが失敗する(または前には思い出せません)。正しく配列のようなオブジェクトとしてオブジェクトを表現するためにあなたの例では

、それは次のようになります。

var arr={0:'a', 1:'b', 2:'c', 3:'d', length: 4} 

は今.forEach()が正常にインデックス0-3を反復します。

1

あなたの推論は間違っています。配列はオブジェクトですが、配列メソッドは任意のオブジェクトで動作するはずです。しかし、specは次のように述べています。

forEach機能は意図的に一般的です。 このの値がArrayオブジェクトであることを は必要としません。したがって、方法として使用するために他の種類のオブジェクトに転送することができます。

もちろん、予想どおりに動作するためには、オブジェクトは配列的に十分でなければなりません。つまり、反復したい配列インデックスより大きい整数の値を持つlengthプロパティを持つ必要があります。あなたは、事前に適切な長さがわからない場合

Array.prototype.forEach.call(
 
    {0:'a', 1:'b', 2:'c', 3:'d', length: 4}, 
 
    function(el){ console.log(el); } 
 
);

、あなたは

console.log(Object.assign([], {0:'a', 1:'b', 2:'c', 3:'d'}).length); // 4

はゲッターを呼び出し、非スキップすることに注意してみてください列挙可能なプロパティ。配列を作成したら、元のオブジェクトではなくforEachを直接呼び出すことができます。

あなたのオブジェクトが一般的である場合は、最初にソートされた整数インデックスを持つキーを返すためにgetOwnPropertyNamesが必要です。アレイの整数インデックスが疎でない場合

var props = Object.getOwnPropertyNames({0:'a', 1:'b', 2:'c', 3:'d'}); 
 
console.log(props.length ? +props[props.length-1]+1 : 0); // 4

、すべてのキーは整数インデックスであると仮定すると、props.lengthを使用することもできます。

関連する問題