「連想配列の操作について(this キーワード)」の記事の中で 連想配列の様に使えるオブジェクトの説明で、そのオブジェクトの中にメソッドを作成し、 オブジェクト内の変数をアクセスする為に this キーワードを使いました。
⇒JavaScript 連想配列の操作について(this キーワード)
今回はこの this キーワードですが、使う場所によって異なるオブジェクトを指し示すため注意が必要です。
以下の使い方がある様ですので、それぞれについて見ていきます。
■グローバル実行コンテクスト
以下のソースを見て下さい。 最初に this キーワードそのものをコンソールにログアウトしています。 結果として this はウインドウオブジェクトであることが分かります。 さらに次のグローバル変数宣言で、ウインドウオブジェクトに value オブジェクトを値「1」で追加します。 これで、ウインドウオブジェクトのプロパティ的に value を参照することが出来ます。
value を「2」として上書きできることも分かります。
ここで注意が必要なのは、存在しない変数をいきなり設定してやると、変数が生成されます。 以下のソースでも value2 が生成されることが分かります。
■関数コンテクスト
グローバル関数の宣言を行って、その中で this キーワードで value を参照しています。 表示される結果は、グローバル変数の内容となります。
■オブジェクトのメソッドとして
オブジェクトを宣言し、その中でメソッドも宣言します。 メソッドの中で this を使ってオブジェクト内のプロパティにアクセスしています。 (このメソッドの定義はインラインでの定義と言うそうです。)
//オブジェクト宣言 var objTest = { value: 100, //オブジェクト内のメソッド宣言 logout: function() { console.log("object value = " + this.value); } }; //メソッド実行 objTest.logout(); // object value = 100 と表示される
このインラインのメソッドを、オブジェクトの外で関数として宣言し、 オブジェクトのプロパティに後から追加することもできます。
//オブジェクト宣言 var objTest = { value: 200 }; //外側で関数宣言 function _logout() { console.log("object value = " + this.value); } //プロパティに関数を割り当てる objTest.logout = _logout; //メソッド実行 objTest.logout(); // object value = 200 と表示される
この例では、オブジェクトのプロパティを logout と宣言するのと、 そのプロパティを _logout 関数に置き換える処理を一緒に行っています。
一緒に行うのがいやであれば、以下の様にしても同じです。
//オブジェクト宣言 var objTest = { value: 200, logout: null //取敢えず先にプロパティ宣言 // logout: 0 }; //外側で関数宣言 function _logout() { console.log("object value = " + this.value); } //プロパティに関数を割り当てる objTest.logout = _logout; //メソッド実行 objTest.logout(); // object value = 200 と表示される
■コンストラクタの呼び出しとして
関数がコンストラクタとして(new キーワードとともに)使用されるとき、 その this は生成された新しいオブジェクトにバインドされます。
以下の例では最初の関数宣言では this を使って内部的にオブジェクトを生成し、そのオブジェクトのプロパティとして value を作り引数の値を設定しています。
この関数をコンストラクタ呼出しを行うと、戻り値としてオブジェクトを返すので、 それを別の変数に代入することで変数を介してそのオブジェクトへアクセスできます。 変数 obj をコンソールに表示させると、オブジェクトが生成されていることが分かります。
//関数宣言 function objCreate(pVal) { this.value = pVal; // value プロパティを pVal で設定 } //コンストラクタ呼出しでオブジェクト生成 var obj = new objCreate(100); console.log(obj); // Object { value: 100 } と表示される
もし new キーワードで使用せずに単に関数呼び出しとした場合はどうなるでしょうか。 以下の例を見て下さい。 単なる関数呼び出しでの this はグローバルオブジェクトを示すため、 この場合ですと Window オブジェクトに value プロパティを生成します。
//関数宣言 function objCreate(pVal) { this.value = pVal; } //単なる関数呼び出し objCreate(100); console.log(this); // Window { objCreate: function objCreate() , value: 100 ... と表示される
■別オブジェクトのバインド呼び出し(call または apply 呼び出し)
関数本体に this キーワードを使用する場合、call メソッドか apply メソッドを使用した呼び出しで、 その値に特定のオブジェクトをバインドできます。
以下の例はオブジェクト「obj」を宣言し、関数の this の指定が「obj」となっていることを示します。
//プロパティ「value」を持つオブジェクト宣言 var obj = { value: "object" }; //グローバルオブジェクトにプロパティ「value」宣言 var value = 'global'; //関数宣言 function objTest() { return this.value; //関数の呼出により[this]の指すものが変わる } var strRet; //通常の関数呼び出し strRet = objTest(); console.log(strRet); // global と表示される //[call]関数呼び出し strRet = objTest.call(obj); // this の指定を「obj」として呼び出し console.log(strRet); // object と表示される //[apply]関数呼び出し strRet = objTest.apply(obj);// this の指定を「obj」として呼び出し console.log(strRet); // object と表示される
call 及び apply の明確な違いは以下の例を見て下さい。 call 呼出しの場合は、 this に対応するオブジェクトの後に引数をそのままの値で設定し、 apply 呼出しの場合は、 this に対応するオブジェクトの後に引数を配列の形で設定します。
//関数宣言(引数が3個) function sum(p3, p4, p5) { //[this]によるプロパティ値と引数の値の合計計算 return this.p1 + this.p2 + p3 + p4 + p5; } //プロパティ[p1][p2]を持つオブジェクト宣言 var obj = { p1: 1, p2: 2 }; var ret; //[call]による関数呼び出し ret = sum.call(obj, 3, 4, 5); console.log(ret); // 15 と表示される //[apply]による関数呼び出し ret = sum.apply(obj, [100, 200, 300]); console.log(ret); // 603 と表示される
コメント