aboutsummaryrefslogtreecommitdiff
path: root/files/ja/mozilla/tech/xpcom/wrappedjsobject/index.html
blob: a51dd2a63084f4096a6c04716874f99333e2bd36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
---
title: wrappedJSObject
slug: Mozilla/Tech/XPCOM/wrappedJSObject
tags:
  - 'XPCOM:Language Bindings'
  - XPConnect
translation_of: Mozilla/Tech/XPCOM/wrappedJSObject
---
<p><code>wrappedJSObject</code><a href="ja/XPConnect">XPConnect</a>ラッパで利用できることがあるプロパティです。利用できる場合、それはあなたに、ラッパによって隠蔽されたJavaScriptオブジェクトへのアクセスを可能にします。
</p><p><code>wrappedJSObject</code>プロパティをサポートするXPConnectラッパには2つの種類があります:
</p>
<ul><li> 内容領域のオブジェクトを操作する際にクロムのコードを保護するために使われる<a href="ja/XPCNativeWrapper">XPCNativeWrapper</a>。詳細な情報は<a href="ja/XPCNativeWrapper">XPCNativeWrapper</a>のページを参照してください。
</li><li> 例えばJavaScriptによって実装されたXPCOMコンポーネントを使う時などに遭遇する、一般的なXPConnectラッパ。
</li></ul>
<p>この項では後者、つまり、コンポーネントが持つプロパティやメソッドのうちxpidlによってサポート済みと宣言されたインターフェースには含まれていない物を隠蔽する種類のラッパについて解説しています。
</p><p>以下、XPConnectラッパが何をするものなのかという事と、<code>wrappedJSObject</code>がそれを迂回するためにどのように使われるのかについて紹介しましょう。
</p><p><span id="Example_component"></span>
</p>
<h3 id="例となるコンポーネント"> 例となるコンポーネント </h3>
<p><code>wrappedJSObject</code>プロパティがどのように働くのかを見るためには、JavaScriptによって実装されたXPCOMコンポーネントの例が必要です。コンポーネントの作成方法の詳細については<a href="ja/How_to_Build_an_XPCOM_Component_in_Javascript">JavaScriptでのXPCOMコンポーネントの作成方法</a>を参照してください。
</p><p>簡単のため、コンポーネントを登録するためのコードは省略します。以下のコンポーネントが<code>@myself.com/my-component;1</code>というコントラクトIDで登録されているものと仮定してください。
</p>
<pre class="eval">// コンストラクタ
function HelloWorld() {
};

HelloWorld.prototype = {
  hello: function() {
    return "Hello World!";
  },

  QueryInterface: function(aIID)
  {
    if (!aIID.equals(Components.interfaces.nsISupports) &amp;&amp;
        !aIID.equals(Components.interfaces.nsIHelloWorld))
      throw Components.results.NS_ERROR_NO_INTERFACE;
    return this;
  }
};
</pre>
<p><span id="XPConnect_wrapping"></span>
</p>
<h3 id="XPConnectによるラッピング"> XPConnectによるラッピング </h3>
<p>それでは上記のコンポーネントへの参照を取得してみましょう。この例では <code>getService</code>を使用していますが、XPCOMから参照を取得する限りにおいては、コンポーネントは常に、XPConnectによってこれと同様にラップされます:
</p>
<pre class="eval">var comp = Components.classes["@myself.com/my-component;1"].getService();
</pre>
<p>コンポーネントの実装において定義した<code>hello()</code>メソッドを呼び出そうとした場合、このような結果が得られます:
</p>
<pre class="eval">&gt; comp.hello();
TypeError on line 1: comp.hello is not a function
</pre>
<p>これは、前述した説明のとおり、<code>comp</code><code>HelloWorld</code>のインスタンスのJavaScriptオブジェクトそのものではなく、XPConnectラッパによって包まれた物であるために起こります:
</p>
<pre class="eval">&gt; dump(comp);
[xpconnect wrapped nsISupports]
</pre>
<p>これらのラッパは、JavaScriptによって実装されたXPCOMコンポーネントを他のXPCOMコンポーネントと全く同じようにユーザに対して見せるようにするという発想に基づいています。これはそのコンポーネントの公開されたインターフェースを明確にし、コンポーネントの内部データを保護する役割も提供します。
</p><p>このラッパに対しては<code>QueryInterface</code>メソッドの呼び出しが利用できますが、それはこのメソッドが<code>nsISupports</code>インターフェースにおいて定義されており、ラッパ自身が、自分がラップしているオブジェクトが<code>nsISupports</code>インターフェースを実装している事を知っているからです:
</p>
<pre class="eval">&gt; comp.QueryInterface(Components.interfaces.nsIHelloWorld);
[xpconnect wrapped (nsISupports, nsIHelloWorld)]
</pre>
<p>この例に見られるように、<code>QueryInterface</code>の呼び出しは、そのラッパに対して、そのコンポーネントが他のインターフェースを実装している事を教えます。<code>nsIHelloWorld</code>インターフェースにおいて<code>hello</code>メソッドが定義されていると仮定すると、それは以下のように呼び出せます:
</p>
<pre class="eval">&gt; comp.hello()
Hello World!
</pre>
<p>この挙動は、そのコンポーネントに対してアクセスするために使われるべきインターフェースを明示的に定義し、コードの開発においてそれを使うよう強制する上で、良い仕組みと言えます。しかし、コンポーネントを試作する場合においてまでインターフェースの定義をいちいち書かなくてはならない(そしてそれを変更する度に再コンパイルしないといけない)のは不便です。
</p><p><span id="Meet_&lt;code>wrappedJSObject&lt;/code>"></span>
</p>
<h3 id="wrappedJSObjectの利用"> <code>wrappedJSObject</code>の利用 </h3>
<p>XPConnectは、それによってラップされたオブジェクト自身が許可している場合、<code>wrapper.wrappedJSObject</code>プロパティを用いて、ラッパを迂回してその中にあるJavaScriptオブジェクトに直接アクセスすることを許容します。
</p><p>より具体的に言うと、<a href="https://dxr.mozilla.org/mozilla-central/source/js/src/xpconnect/idl/nsIXPConnect.idl" rel="custom">XPConnectのソース中のコメント</a>にあるとおり、<code>comp.wrappedJSObject</code>は以下の3つの条件が満たされている場合に利用できます:
</p>
<ul><li> <code>comp</code>が本当にJavaScriptオブジェクトをラップしたXPConnectラッパであること。JavaScriptオブジェクト以外に対するラッパはこのプロパティを持ちません。
</li><li> ラップされたオブジェクトが<code>wrappedJSObject</code>プロパティを持っており、そのプロパティが値としてJavaScriptオブジェクトを返すこと。
</li><li> <code>nsIXPCSecurityManager</code>がアクセスを許可していること。(詳細はソース中のコメントを参照してください。Mozilla拡張機能やアプリケーションにおいては大抵の場合は問題ありません。)
</li></ul>
<p>これは、コンポーネントを実装しているJavaScriptオブジェクトに直接アクセスできるようにするためにコンポーネントを修正する必要があるということです。例えば以下のようにします:
</p>
<pre class="eval">function HelloWorld() {
  <b>this.wrappedJSObject = this;</b>
};
</pre>
<p>これで、コンポーネントを直接取得できるようになりました:
</p>
<pre class="eval">var comp = Components.classes["@myself.com/my-component;1"]
                     .getService()<b>.wrappedJSObject</b>;
</pre>
<p>これは本物のJavaScriptオブジェクトです:
</p>
<pre class="eval">&gt; comp
[object Object]
</pre>
<p>なので、あらゆるプロパティにアクセスすることができます:
</p>
<pre class="eval">&gt; comp.hello();
Hello World!
</pre>
<p>この機能は、試作を手軽に行うために利用できるほか、型が不定なJavaScriptの値をコンポーネントに簡単に渡すためにも利用できます。(具体的には、<a href="ja/Working_with_windows_in_chrome_code#Using_an_XPCOM_singleton_component">完全なJavaScriptのデータを共有する</a>など。)
</p>
<div class="noinclude">
</div>