JavaScriptのthisとPHPのthis

## どんな記事？

JavaScriptとPHPのthisを**比べながら**理解しよう。

## 背景

thisがよく分からん！
↓
JavaScriptの`this`は**他の言語と少々異なる動作**をするらしい
↓
よろしい、ならば比較だ

## PHPのthis

PHPの**疑似変数**である`$this`は、メソッドがオブジェクトコンテキストからコール場合に利用することができる。
`$this`は呼び出し元オブジェクトへの参照である。

カレントオブジェクトからそのクラス内の関数や変数にアクセスする場合に`$this`を使える。

(コンテキストは直訳だと**文脈**という意味。
プログラミング用語的には、**背景となる情報**という言い回しが妥当かな？)

(カレントオブジェクトとは、インスタンスメソッドが起動されたオブジェクトのこと）

```php
<?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`クラスの中で

```php
$sample->$hoge
```
と書くことはできないのである。

代わりに、**クラスの中から、そのクラス内の関数や変数にアクセスする**為に`$this`を使う。

## JavaScriptのthis

> ほとんどの場合、`this`の値は、関数の呼ばれ方によって決定されます。これは実行時に割り当てできず、関数が呼び出されるたびに異なる可能性があります。

ほう。


### 構文
```
this
```
> 値：現在のコードが実行されているJavaScriptコンテキストオブジェクトです

### グローバルコンテキスト

JavaScriptにおける**グローバル実行コンテキスト**(いずれかの関数の外側)では、
`this`はグローバルオブジェクトを参照する。

```javascript:例文
//whidowはグローバルオブジェクト
//thisはグローバルオブジェクトを示す
console.log(this === window);  // true

//グローバルオブジェクトで宣言
this.hoge = 37;
//windowグローバルオブジェクトから
//thisで宣言した値を呼び出すことができる
console.log(window.hoge); //出力結果：37
```

あれ、PHPとぜんぜん違いますね（驚愕）

### 関数コンテキスト

#### 単純な呼び出し

次の例は呼び出し時に`this`の値がセットされない為、`this`はデフォルトでグローバルオブジェクトとなり、それはブラウザでは`window`と同等である。

```javascript
funcion f1() {
  return this;
}

f1() === window; //出力結果：true
```


別のコンテキストから`this`の値を呼び出す場合は`call`もしくは`apply`を使用する。

```javascript
//オブジェクト定義
var obj = {a: 'Custom'};

function whatsThis() {
  return this.a;
}

whatsThis.call(obj); //出力結果：Custom
```

#### アロー関数

アロー関数では、`this`はそれを囲むレキシカル（静的）なコンテキストの`this`の値が設定される。

```javascript
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); //出力結果：true
```

### オブジェクトのメソッドとして

関数がオブジェクトのメソッドとして呼び出される時、その`this`にはメソッドが呼び出されたオブジェクトが設定される。

次の例では`test.func()`が起動した時、関数内の`this`には`test`オブジェクトが関連付けられる。

```javascript
const test = {
  prop: 42,
  func: function () {
    retrun this.prop;
  },
};

console.log(test.func());
//出力結果: 42
```

この振る舞いは、関数定義の方法や場所に全く影響を受けない。

#### オブジェクトのプロトタイプチェーン上の`this`

同じ概念が、オブジェクトのプロトタイプチェーンのどこかに定義されたメソッドにもあてはまる。
そのメソッドがオブジェクト上にあるかのように、`this`はメソッドを呼び出したオブジェクトを参照する。

```javascript
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`は生成された新しいオブジェクトにバインド（拘束）される

```javascript
//関数定義
function C() {
  this.a = 37;
}
//コンストラクタ生成
var o = new C();
console.log(o.a); //出力結果:37
```

### DOMイベントハンドラとして

関数がイベントハンドラとして使用される場合、その`this`にはイベントを発火させた要素が設定される

```javascript
//要素を青色にする関数
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](https://www.php.net/manual/ja/language.oop5.basic.php)
[PHPで擬似変数$thisって何のためにあるのか？](https://ts0818.hatenablog.com/entry/2015/10/03/215418)
[this - JavaScript|MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/this)
[「コンテキスト」という言葉が何を指しているのかよく分からない](https://ja.stackoverflow.com/questions/30060/%e3%82%b3%e3%83%b3%e3%83%86%e3%82%ad%e3%82%b9%e3%83%88-%e3%81%a8%e3%81%84%e3%81%86%e8%a8%80%e8%91%89%e3%81%8c%e4%bd%95%e3%82%92%e6%8c%87%e3%81%97%e3%81%a6%e3%81%84%e3%82%8b%e3%81%ae%e3%81%8b%e3%82%88%e3%81%8f%e5%88%86%e3%81%8b%e3%82%89%e3%81%aa%e3%81%84)
[レキシカルスコープとクロージャを理解する](https://wemo.tech/904)