スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

カテゴリ : スポンサー広告

コンテキストの話①

■吉里吉里/KAG/TJS雑談質問スレ■その25の>>815からちょっとでてたので。
そこで書かれていてることが全てですが具体例付きで丁寧な説明。


TJSリファレンス>データ型>オブジェクト型より引用
http://devdoc.kikyou.info/tvp/docs/tjs2doc/contents/types.html
「オブジェクト型は、オブジェクトを保持する型です。new 演算子で確保したオブジェクトのほか、関数、クラス、プロパティオブジェクトなどはすべてオブジェクト型になります。
typeof 演算子は、これに対しては "Object" を返します。

TJS や JavaScript と異なり、TJS2 のオブジェクト型は、オブジェクトそのものへのポインタと、それが使用されるべきコンテキストとなるオブジェクトのポインタの2つのポインタを内部に持っていて、いわゆるクロージャを実現できるようになっています。
このコンテキスト部分を変更する演算子が incontextof 演算子です。」



コンテキストがあるのはオブジェクト型の変数のみです。
「123」のような整数や「"あいうえお"」のような文字列にはコンテキストは有りません。

オブジェクトは「そのオブジェクトそのもの」と、「コンテキスト用のオブジェクト」の2つから成り立っています。
ポインタ、というのはまあどうでもいいです。


var moge = "グローバルmoge";
function hoge() {
  System.inform(moge);
}
hoge();
関数もオブジェクト型です。
コンテキストが重要になるのは大抵関数なので関数を具体例として取り上げながら説明していきます。

この「hoge」関数で説明すると、オブジェクトそのものとは「System.inform(moge);」のような中身のことです。
moge変数の中身を表示します。
コンテキスト用のオブジェクトは、グローバル関数の場合はglobalになっています。

コンテキスト(context)とは、直訳すると文脈です。
変数を探すときにどこから探してくるのか、ということです。
この関数が実行された時にmoge変数を表示するには、moge変数を探してこなければなりません。
今回はすぐ上でglobalで宣言しているmogeが見つかって「グローバルmoge」と表示されます。


var moge = "グローバルmoge";
class HogeClass
{
  var moge = "クラスのmoge";
  function hoge() {
    System.inform(moge);
  }
}
var h = new HogeClass(); // インスタンスの作成
h.hoge();
クラスに含まれる関数は、そのクラスをnewしたときに、そのnewで生成されたオブジェクトをコンテキストとして登録されます。
var h = new HogeClass();();」で、HogeClassのインスタンスが作られます。
このインスタンスにはhoge関数が含まれますが、この関数オブジェクト(h.hoge)のコンテキストはglobalではなくこのインスタンス(h)です。
hには「var moge = "クラスのmoge";」としてmoge変数も含まれています。
「h.hoge();」で関数が呼び出されると、コンテキストであるhからmogeを探し、mogeがあるのでその「"クラスのmoge"」が表示されることになります。


var moge = "グローバルmoge";
class HogeClass
{
  var moge = "クラスのmoge";
  function hoge() {
    System.inform(moge);
  }
}
var h = new HogeClass();
delete h.moge; // 関数を実行する前にh.mogeを削除
h.hoge();
先程とは変わって、h.hogeを呼び出す前に、「delete h.moge;」でhに含まれるmoge変数を削除しています。
「h.hoge();」で関数が呼び出されると、コンテキストであるhからmogeを探すところまでは同じです。
しかし、hの中のmogeは既に削除されていて見つかりません。
この場合、globalまで行って探しに行ってくれます。
すると「var moge = "グローバルmoge";」として宣言されているグローバルのmoge変数が見つかるので、「グローバルmoge」と表示されます。


function hoge() {
  System.inform(this);
}
hoge();
オブジェクトの中では、「this」を使うとコンテキストにアクセスできます。
これを実行すると、「(object 0x02878824:0x02878824)」のような、よくわからないものが表示されます。
前述のとおりhoge関数のコンテキストはglobalのはずです。それを確かめてみます。


function hoge() {
  System.inform(this == global);
}
hoge();
これを実行するとtrueを示す1が表示されます。
thisglobalは一致しています。


var moge = "グローバルmoge";
class HogeClass
{
  var moge = "クラスのmoge";
  function hoge() {
    System.inform(moge);
  }
}
var h = new HogeClass(); // インスタンスの作成
var tmp = h.hoge;
tmp(); // "クラスのmoge"が表示される。
tmp = (h.hoge incontextof global);
tmp(); // "グローバルmoge"が表示される。
incontextof演算子を使うと、コンテキストを変更したオブジェクトが得られます。
var tmp = h.hoge;」では、そのまま代入しているのでtmpとh.hogeは全く同じ物になります。
つまり、tmpとh.hogeはどちらも「System.inform(moge);」という関数の中身を持ち、「new HogeClass()」で生成されたオブジェクトがコンテキストとなっている関数オブジェクトです。

1つ目の「tmp();」では、「h.hoge();」とするのと同じで、「クラスのmoge」が表示されます。

「tmp = (h.hoge incontextof global);」ではどうなるでしょうか。
このtmpは、中身はそのまま「System.inform(moge);」のような関数ですが、コンテキストはglobalとなっている新しい関数オブジェクトです。
h.hogeとはコンテキストが違っています。
2つ目の「tmp();」では、System.inform(moge);という中身が実行されますが、mogeを探す先はglobalです。
よって「グローバルmoge」が表示されます。


var moge = "グローバルmoge";
class HogeClass
{
  var moge = "クラスのmoge";
  function hoge() {
    System.inform(moge);
  }
}
var h = new HogeClass(); // インスタンスの作成
h.hoge(); // "クラスのmoge"が表示される。
(h.hoge incontextof global)(); // "グローバルmoge"が表示される。
先程とは違って、いちいちtmp変数に代入せずにすぐに呼び出していますが、実行結果は同じになります。


var moge = "グローバルmoge";
function hoge() {
  global.System.inform(moge);
}
hoge();
var dic = %[ "moge" => "辞書のmoge" ];
(hoge incontextof dic)();
辞書もオブジェクトなのでコンテキストとして使えます。
「(hoge incontextof dic)();」ではコンテキストをdicに変更した関数を呼び出しているので、moge変数を探すときに辞書の中から探されます。
よって「辞書のmoge」が表示されます。

この時に注意なのですが、「global.System.inform(moge);」のようにglobalをつけています。
つけずに「System.inform(moge);」とすると、「(void) から Object へ型を変換できません。」のようなエラーが出ます。

「System」というのも吉里吉里側でglobalにあらかじめ宣言されているただの変数です。
実行時にはコンテキストからSystemを探します。
コンテキストがglobalの時はもちろん問題なく見つかります。
HogeClassの例のように、コンテキストがクラスインスタンスであっても、インスタンスの中に見つからなければglobalまで自動的に探しに行ってくれるので問題ありません。

しかし、コンテキストが辞書のときはそうは行きません。
存在しない変数はglobalまで探しに行かずにvoidとなってしまいます。
「System.inform(moge);」としてしまうと、Systemが見つからずにvoidとなってしまいます。
つまり「void.inform」となって、voidをオブジェクトに変換しようとして失敗するのでエラーが発生します。


コンテキストが辞書ではなく、クラスの場合でも問題が起きることがあります。
class HogeClass
{
  function HogeClass() {}

  function hoge() {
    var localH = new HogeClass();
    localH.moge();
  }

  function moge() {
    System.inform("mogeが呼ばれました。");
  }
}
var h = new HogeClass();
h.hoge();
これを実行すると、「関数ではないかプロパティの種類が違います」というエラーとなります。l
問題となるのは「var localH = new HogeClass();」です。
実行時にHogeClassをコンテキストである同じインスタンスの中から探し始めます。
このとき、コンストラクタである「HogeClass」関数が見つかってしまいます。
globalに宣言されているHogeClassクラスまで探しに行くまえに見つかってしまうのです。
関数をnewすることは出来ないのでエラーとなります。
var localH = new global.HogeClass();」のようにglobalにあるHogeClassであることを示せば正しく動作し、「mogeが呼ばれました」と表示されます。
スポンサーサイト

タグ : 吉里吉里 TJS

カテゴリ : TJS

コメントの投稿

非公開コメント

最新記事
カテゴリ

openclose

記事一覧
Twitter
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。