どんな記事?
JavaScriptとPHPのthisを比べながら理解しよう。
背景
thisがよく分からん!
↓
JavaScriptのthis
は他の言語と少々異なる動作をするらしい
↓
よろしい、ならば比較だ
PHPのthis
PHPの疑似変数である$this
は、メソッドがオブジェクトコンテキストからコール場合に利用することができる。
$this
は呼び出し元オブジェクトへの参照である。
カレントオブジェクトからそのクラス内の関数や変数にアクセスする場合に$this
を使える。
(コンテキストは直訳だと文脈という意味。
プログラミング用語的には、背景となる情報という言い回しが妥当かな?)
(カレントオブジェクトとは、インスタンスメソッドが起動されたオブジェクトのこと)
<?php
//クラス(Sample)
class Sample
{
//プロパティ($hoge)宣言
public $hoge = 'foo';
//メソッド(display)宣言
public function display()
{
//displayメソッドで$hogeの内容を呼び出す
echo $this->$hoge;
}
}
$sample = new Sample;
$sample->display(); //出力結果:foo
?>
なぜ$this
が必要か?
それは、
クラス定義の内部では、それにアクセス可能なオブジェクト名を知ることができない
からである。
上記サンプルでは、Sample
クラスが書かれている時点では、
そのオブジェクトの名前があとで$sample
になるのか、はたまた$show
になるのか分からない。
その為、Sample
クラスの中で
$sample->$hoge
と書くことはできないのである。
代わりに、クラスの中から、そのクラス内の関数や変数にアクセスする為に$this
を使う。
JavaScriptのthis
ほとんどの場合、
this
の値は、関数の呼ばれ方によって決定されます。これは実行時に割り当てできず、関数が呼び出されるたびに異なる可能性があります。
ほう。
構文
this
値:現在のコードが実行されているJavaScriptコンテキストオブジェクトです
グローバルコンテキスト
JavaScriptにおけるグローバル実行コンテキスト(いずれかの関数の外側)では、
this
はグローバルオブジェクトを参照する。
//whidowはグローバルオブジェクト
//thisはグローバルオブジェクトを示す
console.log(this === window); // true
//グローバルオブジェクトで宣言
this.hoge = 37;
//windowグローバルオブジェクトから
//thisで宣言した値を呼び出すことができる
console.log(window.hoge); //出力結果:37
あれ、PHPとぜんぜん違いますね(驚愕)
関数コンテキスト
単純な呼び出し
次の例は呼び出し時にthis
の値がセットされない為、this
はデフォルトでグローバルオブジェクトとなり、それはブラウザではwindow
と同等である。
funcion f1() {
return this;
}
f1() === window; //出力結果:true
別のコンテキストからthis
の値を呼び出す場合はcall
もしくはapply
を使用する。
//オブジェクト定義
var obj = {a: 'Custom'};
function whatsThis() {
return this.a;
}
whatsThis.call(obj); //出力結果:Custom
アロー関数
アロー関数では、this
はそれを囲むレキシカル(静的)なコンテキストのthis
の値が設定される。
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); //出力結果:true
オブジェクトのメソッドとして
関数がオブジェクトのメソッドとして呼び出される時、そのthis
にはメソッドが呼び出されたオブジェクトが設定される。
次の例ではtest.func()
が起動した時、関数内のthis
にはtest
オブジェクトが関連付けられる。
const test = {
prop: 42,
func: function () {
retrun this.prop;
},
};
console.log(test.func());
//出力結果: 42
この振る舞いは、関数定義の方法や場所に全く影響を受けない。
オブジェクトのプロトタイプチェーン上のthis
同じ概念が、オブジェクトのプロトタイプチェーンのどこかに定義されたメソッドにもあてはまる。
そのメソッドがオブジェクト上にあるかのように、this
はメソッドを呼び出したオブジェクトを参照する。
var o = {
f: function() {
return this.a + this.b
}
}
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); //出力結果:5
コンストラクタとして
関数がコンストラクタとして(new
で生成される)使用される時、そのthis
は生成された新しいオブジェクトにバインド(拘束)される
//関数定義
function C() {
this.a = 37;
}
//コンストラクタ生成
var o = new C();
console.log(o.a); //出力結果:37
DOMイベントハンドラとして
関数がイベントハンドラとして使用される場合、そのthis
にはイベントを発火させた要素が設定される
//要素を青色にする関数
function bluify(e) {
console.log(this === e.currentTarget);
console.log(this === e.target);
this.style.backgroundColor = '#A5D9F3';
}
//全ての要素を取得
var elements = document.getElementByTagName('*');
//クリックリスナーとしてbluify関数を設定
//クリックした要素が青色に変わる
for(var i = 0; i < elements.length; i++){
elements[i].addEventListener('click', bluify, false);
}
比べてみて
JavaScriptのthis
は、オブジェクトのメソッドやコンストラクトとして使うのであればPHPと同じような理解でいいのかな、と思いました。
DOMイベントハンドラとしてはフロントエンドならでは、という感じですね。
グローバルコンテキスト・関数コンテキストでのthis
は、まだ使い道が分からん...
参考
PHP: クラスの基礎 - Manual
PHPで擬似変数$thisって何のためにあるのか?
this - JavaScript|MDN
「コンテキスト」という言葉が何を指しているのかよく分からない
レキシカルスコープとクロージャを理解する