JavaScriptの最初のバージョンでは、配列はありませんでした。それらは後に、その「すべてのオブジェクトの母」のサブクラスとして導入されました:Object
。これを行うことで、これを非常に簡単にテストできます。
var foo = [1,2,3,4];
for (var n in foo)
{//check if n is equal (value and type) to itself, coerced to a number
console.log(n === +(n) ? 'Number' : 'String');
}
これにより、何度も何度もログString
に記録されます。内部的には、すべての数値キーが文字列に変換されます。Lengthプロパティは、最も高いインデックスをフェッチし、それに1を追加するだけです。これ以上何もない。配列を表示すると、オブジェクトが繰り返され、キーごとに、他のオブジェクトと同じルールが適用されます。最初にインスタンスがスキャンされ、次にプロトタイプがスキャンされます。コードを少し変更すると、次のようになります。
var foo = [1,2,3,4];
foo[9] = 5;
for (var n in foo)
{
if (foo.hasOwnProperty(n))
{//check if current key is an array property
console.log(n === +(n) ? 'Number' : 'String');
}
}
undefined
インスタンス内にも、基になるプロトタイプにも対応する値が見つからなかったため、配列には5つの独自のプロパティしかなく、キー4〜8は未定義であることがわかります。つまり、配列は実際には配列ではありませんが、同様に動作するオブジェクトです。
Timが述べたように、そのオブジェクト内に存在する未定義のプロパティを持つ配列インスタンスを持つことができます。
var foo = [1,2,undefined,3];
console.log(foo[2] === undefined);//true
console.log(foo[99] === undefined);//true
しかし、繰り返しになりますが、違いがあります。
console.log((foo.hasOwnProperty('2') && foo[2] === undefined));//true
console.log((foo.hasOwnProperty('99') && foo[99] === undefined));//false
要約、あなたの3つの主な質問:
アップデート:
Ecma stdを引用するだけです:
15.4配列オブジェクト
配列オブジェクトは、特定のクラスのプロパティ名に特別な扱いをします。プロパティ名P(文字列値の形式)は、ToString(ToUint32(P))がPに等しく、ToUint32(P)が2 ^32-1に等しくない場合にのみ、配列インデックスになります。プロパティ名が配列インデックスであるプロパティは、要素とも呼ばれます。すべての配列オブジェクトには、値が常に2^32未満の非負の整数であるlengthプロパティがあります。lengthプロパティの値は、名前が配列インデックスであるすべてのプロパティの名前よりも数値的に大きくなります。Arrayオブジェクトのプロパティが作成または変更されるたびに、この不変条件を維持するために必要に応じて他のプロパティが調整されます。具体的には、名前が配列インデックスであるプロパティが追加されるたびに、必要に応じて長さプロパティが変更されます。その配列インデックスの数値より1つ多くなります。また、lengthプロパティが変更されるたびに、名前が新しい長さ以上の値を持つ配列インデックスであるすべてのプロパティが自動的に削除されます。この制約は、Arrayオブジェクトの独自のプロパティにのみ適用され、プロトタイプから継承される可能性のある長さや配列インデックスのプロパティの影響を受けません。
次のアルゴリズムがtrueを返す場合、オブジェクトOはスパースであると言われます
。1。引数"length"を指定してOの[[Get]]内部メソッドを呼び出した結果をlenとします。
2.0≤iaの範囲の整数iごと
に。elemを、引数ToString(i)を使用してOの[[GetOwnProperty]]内部メソッドを呼び出した結果とします。
b。elemが未定義の場合、trueを返します。
3.falseを返します。