--- title: wrappedJSObject slug: Mozilla/Tech/XPCOM/wrappedJSObject tags: - 'XPCOM:Language Bindings' - XPConnect translation_of: Mozilla/Tech/XPCOM/wrappedJSObject ---
wrappedJSObjectはXPConnectラッパで利用できることがあるプロパティです。利用できる場合、それはあなたに、ラッパによって隠蔽されたJavaScriptオブジェクトへのアクセスを可能にします。
wrappedJSObjectプロパティをサポートするXPConnectラッパには2つの種類があります:
この項では後者、つまり、コンポーネントが持つプロパティやメソッドのうちxpidlによってサポート済みと宣言されたインターフェースには含まれていない物を隠蔽する種類のラッパについて解説しています。
以下、XPConnectラッパが何をするものなのかという事と、wrappedJSObjectがそれを迂回するためにどのように使われるのかについて紹介しましょう。
wrappedJSObjectプロパティがどのように働くのかを見るためには、JavaScriptによって実装されたXPCOMコンポーネントの例が必要です。コンポーネントの作成方法の詳細についてはJavaScriptでのXPCOMコンポーネントの作成方法を参照してください。
簡単のため、コンポーネントを登録するためのコードは省略します。以下のコンポーネントが@myself.com/my-component;1というコントラクトIDで登録されているものと仮定してください。
// コンストラクタ
function HelloWorld() {
};
HelloWorld.prototype = {
hello: function() {
return "Hello World!";
},
QueryInterface: function(aIID)
{
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.nsIHelloWorld))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
それでは上記のコンポーネントへの参照を取得してみましょう。この例では getServiceを使用していますが、XPCOMから参照を取得する限りにおいては、コンポーネントは常に、XPConnectによってこれと同様にラップされます:
var comp = Components.classes["@myself.com/my-component;1"].getService();
コンポーネントの実装において定義したhello()メソッドを呼び出そうとした場合、このような結果が得られます:
> comp.hello(); TypeError on line 1: comp.hello is not a function
これは、前述した説明のとおり、compがHelloWorldのインスタンスのJavaScriptオブジェクトそのものではなく、XPConnectラッパによって包まれた物であるために起こります:
> dump(comp); [xpconnect wrapped nsISupports]
これらのラッパは、JavaScriptによって実装されたXPCOMコンポーネントを他のXPCOMコンポーネントと全く同じようにユーザに対して見せるようにするという発想に基づいています。これはそのコンポーネントの公開されたインターフェースを明確にし、コンポーネントの内部データを保護する役割も提供します。
このラッパに対してはQueryInterfaceメソッドの呼び出しが利用できますが、それはこのメソッドがnsISupportsインターフェースにおいて定義されており、ラッパ自身が、自分がラップしているオブジェクトがnsISupportsインターフェースを実装している事を知っているからです:
> comp.QueryInterface(Components.interfaces.nsIHelloWorld); [xpconnect wrapped (nsISupports, nsIHelloWorld)]
この例に見られるように、QueryInterfaceの呼び出しは、そのラッパに対して、そのコンポーネントが他のインターフェースを実装している事を教えます。nsIHelloWorldインターフェースにおいてhelloメソッドが定義されていると仮定すると、それは以下のように呼び出せます:
> comp.hello() Hello World!
この挙動は、そのコンポーネントに対してアクセスするために使われるべきインターフェースを明示的に定義し、コードの開発においてそれを使うよう強制する上で、良い仕組みと言えます。しかし、コンポーネントを試作する場合においてまでインターフェースの定義をいちいち書かなくてはならない(そしてそれを変更する度に再コンパイルしないといけない)のは不便です。
wrappedJSObjectの利用 XPConnectは、それによってラップされたオブジェクト自身が許可している場合、wrapper.wrappedJSObjectプロパティを用いて、ラッパを迂回してその中にあるJavaScriptオブジェクトに直接アクセスすることを許容します。
より具体的に言うと、XPConnectのソース中のコメントにあるとおり、comp.wrappedJSObjectは以下の3つの条件が満たされている場合に利用できます:
compが本当にJavaScriptオブジェクトをラップしたXPConnectラッパであること。JavaScriptオブジェクト以外に対するラッパはこのプロパティを持ちません。
wrappedJSObjectプロパティを持っており、そのプロパティが値としてJavaScriptオブジェクトを返すこと。
nsIXPCSecurityManagerがアクセスを許可していること。(詳細はソース中のコメントを参照してください。Mozilla拡張機能やアプリケーションにおいては大抵の場合は問題ありません。)
これは、コンポーネントを実装しているJavaScriptオブジェクトに直接アクセスできるようにするためにコンポーネントを修正する必要があるということです。例えば以下のようにします:
function HelloWorld() {
this.wrappedJSObject = this;
};
これで、コンポーネントを直接取得できるようになりました:
var comp = Components.classes["@myself.com/my-component;1"]
.getService().wrappedJSObject;
これは本物のJavaScriptオブジェクトです:
> comp [object Object]
なので、あらゆるプロパティにアクセスすることができます:
> comp.hello(); Hello World!
この機能は、試作を手軽に行うために利用できるほか、型が不定なJavaScriptの値をコンポーネントに簡単に渡すためにも利用できます。(具体的には、完全なJavaScriptのデータを共有するなど。)