概要
XPCOM コンポーネントの新規インスタンスを作成/生成するのに使用できる JavaScript 関数を作成します。
構文
var func = [ new ] Components.Constructor(contractID [, interfaceName [, initializer ] ]);
パラメータ
-
contractID
- コンポーネントのコントラクト ID を含む文字列
-
interfaceName
- 与えられると、新規作成されるインスタンスそれぞれに対してこの文字列の名前のインターフェイスで QueryInterface が呼び出される
-
initializer
- 与えられると、この文字列の名前の関数が、新規作成されるインスタンスに対してその時に与えられる引数を使って呼び出される
説明
Components.Constructor()
は XPCOM コンポーネントのインスタンス作成に便利なショートカットです。これを使うと、インスタンスを作りたい時に毎回 Components.classes
、Components.interfaces
、createInstance
などをタイピングする手間が無くなります。また、より JavaScript 的な構文で XPCOM オブジェクトを作成できるようになります。もう一つの重要な恩恵として、Components.Constructor()
はいくつかの計算をあらかじめ行うので、Components.Constructor()
から返される関数を使って XPCOM オブジェクトを作成した方が下記に示すように基本原則に基づいてオブジェクトを作成するよりも高速になります。 (JavaScript エンジンと XPCOM の間のレイヤーをまたぐ回数がより少なくて済むというのも高速になる理由の一つです。)
Components.Constructor()
によって返される関数のふるまいは、 Components.Constructor()
が呼び出されたときに与えられた引数によって異なります。与えられた引数が 1 つだけなら、その引数は作成される XPCOM コンポーネントのコントラクト ID になります。コンポーネントはすぐ返されますが、そのコンポーネントからは基本インターフェイスの nsISupports
しか利用できません。なのでそのオブジェクトのメソッドを呼び出すためにはそれに対して QueryInterface を呼び出さなければなりません。例えば、
var BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1"); var bis = new BinaryInputStream(); print(bis.toString()); // "[xpconnect wrapped nsISupports]" try { // someInputStream は既存の nsIInputStream // bis は nsIBinaryInputStream に QI されていないのでエラーを投げる bis.setInputStream(someInputStream); } catch (e) { bis.QueryInterface(Components.interfaces.nsIBinaryInputStream); bis.setInputStream(someInputStream); // これで成功 }
引数が 2 つ与えられると、作成されるインスタンスは第 2 引数の名前を持つ XPCOM インターフェイスに QueryInterface
されます。
var BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream"); var bis = new BinaryInputStream(); print(bis.toString()); // "[xpconnect wrapped nsIBinaryInputStream]" // someInputStream は既存の nsIInputStream bis.setInputStream(someInputStream); // 成功
引数が 3 つ与えられると、インスタンスに対して QueryInterface
されるだけでなく、初期化メソッドも呼び出されたことになります。初期化メソッドに使われる引数は、Components.Constructor()
によって作成された関数を呼び出す時に渡された引数です。
var BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream", "setInputStream"); try { // 引数の数が nsIBinaryInputStream.setInputStream が // 取るものと異なるのでエラーを投げる var bis = new BinaryInputStream(); } catch (e) { // someInputStream は既存の nsIInputStream bis = new BinaryInputStream(someInputStream); // 成功 var bytes = bis.readByteArray(someNumberOfBytes); // 成功 }
基本原則に基づいたインスタンスの作成と Components.Constructor()
を使ったインスタンスの作成を比較して下さい。後者の方が前者よりもずっと (たくさんの違う場所でコンポーネントのインスタンスを作成している場合には特に) 読みやすくなります。
var bis = Components.classes["@mozilla.org/binaryinputstream;1"] .createInstance(Components.interfaces.nsIBinaryInputStream); bis.setInputStream(someInputStream);
// 前もって BinaryInputStream が初期化されているとして var bis = new BinaryInputStream(someInputStream);
Components.Constructor()
は、他の一般的なメソッドを使って実現できる挙動のシンタックスシュガーに過ぎません (高速できれいなシンタックスシュガーですが)。 次の JavaScript 関数と等価です。
function Components_Constructor(contractID, interfaceName, initializer) { var ccArgs = arguments; function ctor() { var instance = Components.classes[contractID] .createInstance(Components.interfaces.nsISupports); if (ccArgs.length > 1) { instance.QueryInterface(Components.interfaces[interfaceName]); if (ccArgs.length > 2) instance[initializer].apply(instance, arguments); } return instance; } return ctor; }