Dojoは、このほかにもオブジェクト指向に関連したAPIを多数持っている。
dojo.mixin(obj, props...)
objをベースに、第2引数以降のオブジェクトが持つ属性やプロパティをミックスしたオブジェクトを返す。obj自体も変更される。
var objA = { a: "a" };
var objB = { b: "b" };
var objC = { c: "c" };
dojo.mixin(objA, objB, objC);
// 結果は { a:"a", b:"b", c:"c" }
console.dir(objA);
dojo.delegate(obj, props)
objを「ラップ」し、同様に振舞うオブジェクトを返す。obj自体は変更されない。propsは省略可能で、指定した場合はそのオブジェクトのプロパティもミックスされる。
objA = { a: "a" };
// objAを「ラップ」して、a2を作成
var a2 = dojo.delegate(objA);
// 結果は {a: "a"}
console.dir(a2);
// ラップ対象を変更する
objA.a = "x";
// a2.aが返す値も"x"になる
// 結果は {a: "x"}
console.dir(a2);
dojo.extend(constructor, props)
constructorのプロトタイプに、propsが持つ属性やメソッドをすべてコピーする。実質上、constructorがpropsを継承したことになる。
// Stringクラスにtrim()メソッドを加える
dojo.extend(String, {
trim: function() {
return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}
});
// 以降、文字列にはtrim()メソッドが使える
// 結果は"aaa"
console.log(" aaa ".trim()));
dojo.hitch(scope, method, ...)
この関数はオブジェクト指向と直接関係があるわけではないが、クラスベースのJavaScriptプログラミングを行っていると頻繁に使うことになるので、覚えておいたほうがよい。
この関数の戻り値は、新しい関数オブジェクトだ。その関数オブジェクトは、引数で指定されたmethodをただ実行するだけのもの。ただし、method実行中のthisコンテキストがscopeで指定されたオブジェクトになる、という点が重要だ。
このメソッドが活躍するのは、window.setTimeout()やDOMのイベントハンドラなどに、クラス内のメソッドを代入する時だ。以下のクラスはsetTimeout()を用いて、2秒後に「こんにちは! <名前>さん」を表示するプログラムであるが、名前が正しく表示されないバグがある。
dojo.declare("DelayHello", null, {
constructor: function(name) {
this.name = name;
// 2秒後にonTimeout()を呼び出すようスケジュール
setTimeout(this.onTimeout, 2000);
},
onTimeout: function() {
alert("こんにちは!" + this.name + "さん!");
}
});
new DelayHello("白石");
期待する結果は「こんにちは!白石さん」であるが、実際の結果は「こんにちは!さん」となる。
このプログラムの問題は、「onTimeout()」の中で「this.name」を参照していることだ。2秒後に呼び出されたonTimeout()は、その呼び出し元であるsetTimeout()のスコープ (windowオブジェクト) 内で動作するので、thisが指すものは当然windowオブジェクトだ。DelayHelloのインスタンスとは関係ない。
これを解決するためには、dojo.hitch()を用いて、onTimeout()内で使用されるthisをDelayHelloのインスタンスに関連付ければよい。setTimeout()を行っている部分を以下のように修正する。
// 2秒後に呼び出されるonTimeout()のスコープを、
// DelayHelloのインスタンス自身に関連付ける
setTimeout(dojo.hitch(this, this.onTimeout), 2000);
もしくは、関数オブジェクトではなく文字列を使用することもできる。
setTimeout(dojo.hitch(this, "onTimeout"), 2000);