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);