Array
Array(配列)は、"123"などのような整数をプロパティ名として持つオブジェクトとして定義されている。通常のオブジェクトとは異なり、以下のような挙動が追加されている。
- プロパティ名が0以上2^32-1未満の整数の場合、そのプロパティ名を配列インデックスと呼ぶ。(→配列のインデックスは0以上2^32-1未満。「2^32未満」ではない点に注意。)
- プロパティlengthの値は、0以上2^32未満であり、Arrayオブジェクトが持っているどのプロパティ名(配列インデックス)よりも大きい値となる。
- 配列インデックスを名前とするプロパティが追加されたら、それに合うようにlengthが調整される。
- lengthを変更したら、そのlength以上の配列インデックスを名前とするプロパティが削除される。
var ary=new Array();
document.write("ary.length="+ary.length+"\n"); //→0
ary[10]=123;
document.write("ary[5]="+ary[5]+"\n"); //→undefined
document.write("ary[10]="+ary[10]+"\n"); //→123
document.write("ary.length="+ary.length+"\n"); //→11
document.write("ary="+ary+"\n"); //→,,,,,,,,,,123
var obj=new Object();
document.write("obj.length="+obj.length+"\n"); //→undefined
obj[10]=123;
document.write("obj[5]="+obj[5]+"\n"); //→undefined
document.write("obj[10]="+obj[10]+"\n"); //→123
document.write("obj.length="+obj.length+"\n"); //→undefined
document.write("obj="+obj+"\n"); //→[object Object]
配列インデックスとして扱われるのは、プロパティ名を32bit負号なし整数に変換してから再度文字列に変換した結果がもとのプロパティ名と一致した場合なので(ECMAScript3rd:15.4)、整数を表す文字列ならなんでも配列インデックスになるわけではない。
var ary = new Array();
ary[0] = 123;
document.write("ary[0]=" + ary[0] + "\n"); //→123
var ary = new Array();
ary["0"] = 123;
document.write("ary[0]=" + ary[0] + "\n"); //→123
var ary = new Array();
ary["+0"] = 123;
document.write("ary[0]=" + ary[0] + "\n"); //→undefined
var ary = new Array();
ary["00"] = 123;
document.write("ary[0]=" + ary[0] + "\n"); //→undefined
var x = 00;
document.write("x=" + x + "\n"); // → 0 つまり00は整数リテラルとしては有効
var x = +0;
document.write("x=" + x + "\n"); // → 0 つまり+0は整数リテラルとしては有効
コンストラクタ
new Array(len) (ただし、lenがNumberの場合)
新しいArrayオブジェクトを作成し、そのlengthプロパティにlenを代入。
new Array(item0, item1, ...)
新しいArrayオブジェクトを作成し、
- length←引数の数
- プロパティi←itemi
Arrayをnewなしで呼び出した場合、new付きで呼び出した場合と同じオブジェクトを返却する。
var ary1=new Array(25);
document.write("ary1.length="+ary1.length+"\n"); //→25
var ary2=new Array("25");
document.write("ary2.length="+ary2.length+"\n"); //→1
var ary3=new Array(25, 26);
document.write("ary3.length="+ary3.length+"\n"); //→2
初期化子
[item0,item1,item2,...,itemn]
指定した値を要素にもつArrayオブジェクトを作成する。
任意のitemiを省略して、カンマが連続してもよい。省略された要素はundefinedになる。
ただし、] の前がカンマで終わっている場合、最後のカンマの後の要素は無いものとされる(indexが与えられない)。
IEはこのルールに従っていない。最後のカンマの後の要素のindexも確保される。
var ary1 = [];
var ary2 = [,];
var ary3 = [,,];
var ary_x = [,,2,3];
var ary_y = [,,2,3,];
var ary_z = [,,2,3,,];
document.write(ary1.length + "\n"); // 0
document.write(ary2.length + "\n"); // 1(Chrome), 2(IE9)
document.write(ary3.length + "\n"); // 2(Chrome), 3(IE9)
document.write(ary_x.length + "\n"); // 4
document.write(ary_y.length + "\n"); // 4(Chrome), 5(IE9)
document.write(ary_z.length + "\n"); // 5(Chrome), 6(IE9)
instanceof, typeof
var ary = new Array(1,2,3,4);
document.write("ary instanceof Array = " + (ary instanceof Array) + "\n"); // true
document.write("typeof ary = " + (typeof ary) + "\n"); // object
var ary2 = [1,2,3,4];
document.write("ary2 instanceof Array = " + (ary2 instanceof Array) + "\n"); // true
document.write("typeof ary2 = " + (typeof ary2) + "\n"); // object
toString, join
ArrayのtoStringはjoin(引数なし)と同じ結果を返す(ECMAScript3rd:15.4.4.2)。join(引数なし)は、各要素を以下のルールで文字列にして,で連結する(ECMAScript3rd:15.4.4.5)。
- undefined, nullは、空文字列。
- それ以外は、ToStringの結果。ここで、ToStringはECMAScriptの型変換の仕様を定義するための説明用の関数で、実在するものではない。
ToString(ECMAScript3rd:9.8)は、Booleanは"true","false", Stringはそれ自体、Numberは(略、多分常識的)。
Objectについては、要するに(ECMAScript3rd:8.6.2.6)
- toStringメソッドの返却値。
- ただし、toStringがprimitive value (Undefined, Null, Boolean, Number, or String)でない場合はvalueOfメソッドの返却値。
- valueOfの返却値もprimitive valueでなければエラー。
注意点としては、
- undefinedとnullと""はいずれも""となり区別がつかない。
- Arrayの要素がオブジェクトでtoStringが定義されていれば、その結果が使われる。
- Arrayがネストしている場合、ネストしたArrayのtoString(=join)の結果が使われる。これは [ ] で囲われた文字列というわけではないので、ネストした内側と外側の区別が付かない文字列になる。
var ary = [];
ary[3] = "value3";
ary[4] = null;
ary[5] = "value5";
document.write(ary.toString() + "\n"); // ,,,value3,,value5
var ary2 = [];
ary2[3] = ["a","b","c"];
ary2[5] = "value5";
document.write(ary2.toString() + "\n"); // ,,,a,b,c,,value5
function Foo(){};
var ary3 = [1,new Foo()];
document.write(ary3.toString() + "\n"); // 1,[object Object]
function Bar(){};
Bar.prototype.toString=function(){return ",,,"};
var ary4 = [1,new Bar()];
document.write(ary4.toString() + "\n"); // 1,,,,
function Baz(){};
Baz.prototype.toString=function(){return {};};
Baz.prototype.valueOf=function(){return {};};
var ary5 = [1,new Baz()];
//document.write(ary5.toString() + "\n"); // Uncaught TypeError: Cannot convert object to primitive value
for-inでの使用
- lengthプロパティにはDontEnumアトリビュートが与えられている→for-inでは列挙されない。
- 利用者が作成したプロパティはfor-inで列挙される。
var ary3=new Array(25, 26);
document.write("ary3.length="+ary3.length+"\n");
ary3.hoge="fuga";
for (var i in ary3) {
document.write("ary3 prop="+i+"\n");
}
ary3.length=2 ary3 prop=0 ary3 prop=1 ary3 prop=hoge
for-inでプロパティが列挙される順番がECMAScript3rd:12.6.4でははっきりしない。
- 列挙する機構は実装依存。
- 順番はオブジェクトによって定義される。(しかし、ArrayやObjectの説明にfor-inでの列挙順番についての定義が見当たらない)
Chrome 23.0.1271.64 で試したところでは
- 配列インデックス → その他のプロパティ の順
- 配列インデックスは番号の小さい順
- 定義された配列インデックスのみ列挙される。
- その他のプロパティは、プロパティが作成された順
var ary = new Array();
ary["hoge"] = "";
ary[100] = "";
ary[23] = "";
ary["a"] = "";
document.write("length " + ary.length + "\n");
for (var i in ary) {
document.write("prop " + i + "\n");
}
length 101 prop 23 prop 100 prop hoge prop a