JScriptの紹介(2)

/ JScript

JScriptのオブジェクト

全てのオブジェクトはプロパティとメソッドを持つことができます。このあたりは他のオブジェクト指向言語と同じです。プロパティではなくメンバ変数とか呼ぶものもありますが同じです。

JScriptではオブジェクトに拡張プロパティを追加することが出来ます。JScriptの組み込みオブジェクトであるObjectに拡張プロパティを追加してアクセスする例を示します。

var object = new Object();
object.id = 100;
object.name = "string1";
object['another property'] = true;
object[1000] = "string2";

var prop1 = 'prop name 1';
var prop2 = 1001

object[prop1] = prop1;
object[prop2] = prop2;

WScript.Echo(object.id,object.name,object[1000]);

for(property in object) {
  WScript.Echo(property + " => " + object[property]);
}

この出力例はこちら

100 string 1 string 2
id => 100
name => string 1
another property => true
1000 => string 2
prop name 1 => prop name 1
1001 => 1001

上から見ていくと、プロパティ名がアルファベットで始まるシンプルなものならドットで区切って代入することで追加できます。プロパティ名が数値や空白を含む文字列の場合は[]を使って連想配列のように書くことが出来ます。[]には実行時に値の決まる変数も使えます。

アクセスの方法は、拡張プロパティの追加のときと同じです。最後の例ではfor-each文でobjectの全てのプロパティにアクセスできることを示しています。

JScriptの配列

オブジェクトの例から、0,1,2,...と順に整数をキーとするプロパティを追加していけば配列のように扱うということが思いつくと思う。実際、JScriptの配列であるArrayオブジェクトとObjectの違いはArrayがプロパティとしてlengthを持つというぐらい。lengthはプロパティのようにふるまってはいるがfor-eachでは列挙されない。

Arrayオブジェクトの振る舞いを示した例を次に示します。

var array = new Array(3);
show(array);

array[0] = 20;
array[2] = true;
show(array);

array[10] = new Object();
array[11] = 'string2';
show(array);

array.id = 100;
array.name = 'first second';
show(array);

function show(array) {
  WScript.Echo('length='+array.length);
  for(i=0; i<array.length; i++) {
    WScript.Echo('array[' + i + ']=' + array[i]);
  }
  for(prop in array) {
    WScript.Echo(prop + ' => ' + array[prop]);
  }
  WScript.Echo('');
}

このコードに対する出力はこちら

length=3
array[0]=undefined
array[1]=undefined
array[2]=undefined

length=3
array[0]=20
array[1]=undefined
array[2]=true
0 => 20
2 => true

length=12
array[0]=20
array[1]=undefined
array[2]=true
array[3]=undefined
array[4]=undefined
array[5]=undefined
array[6]=undefined
array[7]=undefined
array[8]=undefined
array[9]=undefined
array[10]=[object Object]
array[11]=string2
0 => 20
2 => true
10 => [object Object]
11 => string2

length=12
array[0]=20
array[1]=undefined
array[2]=true
array[3]=undefined
array[4]=undefined
array[5]=undefined
array[6]=undefined
array[7]=undefined
array[8]=undefined
array[9]=undefined
array[10]=[object Object]
array[11]=string2
0 => 20
2 => true
10 => [object Object]
11 => string2
id => 100
name => first second

この例からわかることを説明する。まず、Arrayオブジェクトはnewするときに配列の要素数を指定できる。この時点でlengthプロパティはその値になり、全ての要素はundefinedである。undefinedである要素はfor-eachで列挙されない。

次に、配列の要素に値を代入するとfor-eachのプロパティとして列挙されるようになる。length以上の整数をキーとする拡張プロパティを追加すると、自動的にlengthプロパティは更新される。そこまでの要素はundefinedである。

最後に、Arrayオブジェクトにも整数以外をキーとする拡張プロパティを追加することができ、Objectと同じようにfor-eachでアクセスできる。このとき、整数以外をキーとする拡張プロパティはlengthプロパティには影響を及ぼさない。Objectの場合で列挙されるのがプロパティのキーであったように、Arrayでもfor-eachを使ったときに列挙されるのは配列要素そのものではなく、そこにアクセスできるキーになる。そこが他の言語のfor-each構文と異なるので注意が必要。

JScriptの多次元配列

直接的には多次元配列はサポートされていない。Arrayを入れ子にすることで一応多次元配列は実現できる。例を示す。

table = array2d(9, 9);
for(i=0; i<9; i++) {
  for(j=0; j<9; j++) {
    table[i][j] = (i+1)*(j+1);
  }
}

function array2d(length1, length2) {
  var a = new Array(length1);
  for(i=0; i<a.length; i++) {
    a[i] = new Array(length2);
  }
  return a;
}

この例では結果を出力していない。table変数は掛け算の九九が代入された2次元配列である。

JScriptの独自オブジェクト

オブジェクト指向言語におけるオブジェクトはメソッドとプロパティを持ちます。この作り方が他のオブジェクト指向言語とは書き方が違います。まずは例を示します。

var id = 0;

function Record(name, description) {
  this.id = id++;
  this.name = name;
  this.desc = description;
}

records = new Array(3);
records[0] = new Record('name1', 'description1');
records[1] = new Record('name2', 'description2');
records[2] = new Record('name3', 'description3');
show(records);

records[0].prop1 = true;
records[0].prop2 = 'prorperty';
show(records);

Record.prototype.title = 'records';
show(records);

function show(records) {
  for(i in records) {
    var line = '';
    for(key in records[i]) {
      line += key + "=" +records[i][key] + ",";
    }
    WScript.Echo(line);
  }
  WScript.Echo('');
}

この例ではRecordオブジェクトのコンストラクタを定義して、配列の各要素に対してRecordオブジェクトを代入します。コンストラクタ内ではthisキーワードが自分そのもののオブジェクトを示します。ここでthisに対して自由に拡張プロパティを追加することでメンバ変数に相当するものを定義します。varキーワードで宣言だけ行うこともできますが宣言しようがしまいがそのプロパティはundefinedになるので意味はありません。

2回目のshow関数の前、特定のRecordオブジェクトに対して拡張プロパティを追加しています。これは既に作成された他のRecordオブジェクトには影響しません。

一方で3回目のshow関数の前、Record.prototypeに対して拡張プロパティを追加すると、既に作成されたRecordオブジェクトを含む全てのRecordオブジェクトに影響します。JScriptにおいて.prototypeはオブジェクトの元になるクラスを表す特別なキーワードです。任意のオブジェクトには.prototypeを経由してそのもととなるクラスに拡張プロパティを追加できます。