C#と諸々

C#がメインで他もまぁ諸々なブログです
おかしなこと書いてたら指摘してくれると嬉しいです(´・∀・`)
つーかコメント欲しい(´・ω・`)

2006/11/19 17:16
前回の記事に続き、JavaScriptでのOOPについて。


前回の記事でほんの少し書いたが、プライベートメソッド内に記述されたthisキーワードは、通常はwindowオブジェクトを参照してしまう。

< そもそもthisキーワードって? >

thisキーワードは、コンテキストオブジェクト を参照するためのキーワードである。
thisキーワードがwindowオブジェクトを参照するということは、その関数のコンテキストオブジェクトがwindowオブジェクトであるということになる。


< なぜコンテキストオブジェクトがwindowオブジェクトになってしまうのか? >

これは、プライベートメソッドの 呼び出し方 に原因がある。
プライベートメソッドは、プライベートフィールドに対して関数を設定することで定義できると、前回説明した。そうすると、プライベートメソッドの呼び出し方は

this.privateMethod1():
や、

obj.privateMethod1();
といった、インスタンス経由での呼び出し方はできないので、

privateMethod1();
という、直接的な呼び出し方になる。

この呼び出し方をすると、その関数のコンテキストオブジェクトがwindowオブジェクトになってしまうのである。 ( むしろ、コンテキストオブジェクトがwindowオブジェクトなのが普通であり、インスタンス経由で呼び出した時が特殊な動作をしている。これについてはこの記事の最後で。 )


< プライベートメソッドのコンテキストオブジェクトを、期待通りにするには? >

これには、Functionオブジェクトの applyメソッド 、または callメソッド を利用する。
applyメソッドとcallメソッドは、コンテキストオブジェクトを指定して関数を実行することができる。

function Hoge()
{
    var privateMethod1 =
        function()
        {
            return this;
        };

    this.privilegedMethod1=
        function()
        {
            var obj1 = privateMethod1(); // windowオブジェクトが返される。
            var obj2 = privateMethod1.apply(this); // Hogeオブジェクトが返される。
        };
}


applyメソッドとcallメソッドの違いは、関数に渡す引数の指定方法のみである。
applyメソッドは、第一引数でコンテキストオブジェクトを受け取り、第二引数で関数に渡す引数の配列を受け取る。
callメソッドは、第一引数でコンテキストオブジェクトを受け取り、第二引数以降で関数に渡す引数を受け取る。

function fuga(arg1, arg2)
{
}

var context = new Object();
var arg1 = 1;
var arg2 = 2;
var args = [arg1, arg2];

fuga.apply(context, args); // applyは第二引数に配列で指定する。
fuga.call(context, arg1, arg2); // callは第二引数以降に指定していく。


< 呼び出し方が原因ということは・・・ >

実は、パブリックメソッドやプレビレッジドメソッドも、同じ呼び出し方をすれば、コンテキストオブジェクトがwindowオブジェクトになる。

function Hoge()
{
}

Hoge.prototype.publicMethod1 =
    function()
    {
        return this;
    };

var hogeObj = new Hoge();
var obj1 = hogeObj.publicMethod1()) // 当然、hogeObjを返してくる。

var func = hogeObj.publicMethod1; // publicMethod1自体をfuncに入れる。
var obj2 =  func() // func()という風に呼び出すと、windowオブジェクトを返してくる。


< インスタンス経由での呼び出しは暗黙的に・・・ >

this.メソッド名()  や、 インスタンス名.メソッド名() といった、インスタンス経由での呼び出し方をすると、そのインスタンスがコンテキストオブジェクトとなる。しかし、applyやcallも使わず、普通に関数を呼び出した場合、コンテキストオブジェクトはwindowオブジェクトとなる。

つまり、インスタンス経由での関数呼び出しは、暗黙的にコンテキストオブジェクトを指定して実行されるのである。 ( 内部でapplyやcallを呼び出しているのか、applyやcallに実装されている処理を直接行っているのかどうかは知らないけど。。。 )
タグ: JavaScript

感謝
大変勉強になります

2006.11.27 23:21 URL | Kick #- [ 編集 ]


Kickさん初めまして。コメントありがとうございます。
私の記事が、少しでも力になれれば何よりです^^

2006.11.28 14:44 URL | よこけん #- [ 編集 ]












トラックバックURL↓
http://csharper.blog57.fc2.com/tb.php/46-3d1832d1