【JavaScript】JavaScriptの 「this」とは 1

※当方駆け出しエンジニアのため、間違っていることも多々あると思いますので、ご了承ください。また、間違いに気付いた方はご一報いただけると幸いです。

[【JavaScript】JavaScriptにおけるクロージャーとは](https://qiita.com/sho_U/items/1d58d5fb7cb11030f24b)

↑こちらの記事に以下の通り記載しました。

>「JavaScriptのスコープには、どの識別子がどの変数を参照するかが静的に決定されるという性質があります。
つまり、どこでinside関数を呼び出そうが、inside内のcountは、outside直下のcountを参照するということですね。

>「this」という特別なキーワードだけは、呼び出し元によって動的に参照先が変わります。」

例えば、

```javascript
function (){
  retrun this;
}
```

このような関数があった時、返却されるthisは呼び出し元によって変化します。

原則として、**this**が参照するのは、ざっくりというと**「呼び出し元自体」**です。



まず、**「呼び出し先が異なる」**とはどういう意味なのか。

まず、以下のような内部処理にthisを含む関数があるとします。

```javascript
function (){
console.log(this.name);
}
```

上記関数が、以下のような**human1**, **human2**オブジェクトのgetNameプロパティーとして定義されているとします。それぞれ、プロパティーに
nameプロパティー(valueは文字列),　getNameプロパティ(valueはメソッド（関数))が定義されています。

```javascript

human1 = {
  name: "Taro",
  getName: function () {
    console.log(this.name);
  }
}

human2 = {
  name: "Ken",
  getName: function () {
    console.log(this.name);
  }
}
```

ちなみにイメージしやすいように、メソッドプロパティーを key : value で記載しましたが、

メソッドの定義部分は以下のように省略してもかけます。

```javascript
human2 = {
  name: "Ken",
  getName() {
    console.log(this.name);
  }
}
```
話を戻しまして

それぞれのメソッドを呼び出してみます。

```javascript
human1.getName();     ・・・※1
//Taro

human2.getName();     ・・・※2
//Ken
```
それぞれ、呼び出し元によって異なる文字列が返ってきました。

どのような動きとなっているのか。

※1の場合、getName()メソッドの呼び出し元は、 **human1**ですね。
つまり、メソッド内部のthisには、 呼び出し元自体の **human1オブジェクト**が参照されるわけですね。

イメージとしては、↓のような感じですね。

```javascript
human1 = {
  name: "Taro",
  getName: function () {
    console.log(human1.name);
  }
}
```
再帰的に、呼び出し元オブジェクトが内部のthisから参照されます。

human2は

```javascript
human2 = {
  name: "Taro",
  getName: function () {
    console.log(human2.name);
  }
}
```
ですね。

なぜ、thisから呼び出し元が参照されるかというと、イメージとしては呼び出し時に暗黙的に、仮引数に、呼び出し元オブジェクトを渡す感じです。
どういうことかといいますと、下のようなイメージです。

```javascript
human1 = {
  name: "Taro",
  getName: function (x) { //暗黙的に呼び出元オブジェクトを仮引数xに渡す。
  this = x;  //thisにxを格納。
    console.log(this.name);
  }
}
console.log(human1.getName(human1));  //暗黙的に呼び出し元オブジェクトを引数に渡す。
```
thisを用いることによって、メソッド内部の定義を共通化できるのです。
これによりクラスからインスタンスを作った際に、それぞのインスタンスが持つインスタンス変数を参照することができます。

呼び出し元の種類によって、参照先が異なります。

| 場所 | Thisの参照先 | 
|:-----------:|:------------:|
| トップレベル(関数の外)  | グローバルオブジェクト        |
| 関数  | グローバルオブジェクト      |
| コンストラクター       | 生成したインスタンス       |
| メソッド    | 呼び出し元のオブジェクト     |
| イベントリスナー         | イベントの発生元          |
| call/applyメソッド       |  引数で指定されたオブジェクト        |


原則は全て、呼び出し元がthisに入るということです。

call/applyメソッドについては、thisの参照先を指定することができます。

一つ一つ例を見ていきます。

###関数の外の場合

```javascript
console.log(this);

//window
```
呼び出し元であるグローバルオブジェクト（windowオブジェクト)が参照されています。

###関数の場合
```javascript
function test() {
  console.log(this);
};

test();

//window
```
同様に呼び出し元であるグローバルオブジェクト（windowオブジェクト)が参照されています。

ちなみに、グローバルオブジェクトがもつプロパティを参照した場合は、当然その値が参照されます。

```javascript
function test() {
  console.log(this.document);
};

test();

//#document
//<html>
// <body>
//   <script src="practice.js"></script>
// </body>
//</html>
```

###コンストラクターの場合

```javascript
class Member {
  constructor(name) {
    this.name = name;
  }
}

let member = new Member("Taro")
console.log(member);

//{name: Taro}

let member2 = new Member("Ken");
console.log(member2);

//{name: Ken}
```
まず、new演算子でインスタンスが作成されて、そのインスタンスがコンストラクターを呼び出します。
(その時の引数はmemberでは Taro)
thisには呼び出し元のmemberインスタンスが参照されているので

```javascript
    this.name = name;

    //これはつまり

    member.name = "Taro"
```
ということで、memberインスタンスのnameプロパティにTaroが入ります。

###メソッドの場合
メソッドの場合は、上記の例通りなので割愛

###イベントリスナーの場合

```html
<div id='checkThis'></div>
```
↑  の上にマウスが乗ったら、色が黄色く変わるというシンプルなコードです。
	
```javascript
let elem = document.getElementById('checkThis');

elem.addEventListener('mouseover', function () {
  this.style.backgroundColor = "Yellow";
}, false);
```

　この場合、thisはイベント発生元である elem　が参照されます。
よって、そのelemのスタイルに背景色黄色を設定し変色させます。

##call/applyメソッドの場合

call/applyメソッドの場合だけ、特殊でthisは呼び出し元が参照されますが、それを
異なるオブジェクトを指定してしまおうというものです。

```javascript
human2 = { name: "Ken" };

human1 = {
  name: "Taro",
  getName: function () {
    console.log(this.name);
  }
}

human1.getName();

//Taro

human1.getName.call(human2);

//Ken
```

普通にgetName()を実行すると、当然human1がthisから参照されます。

しかし、callメソッドで引数にhuman2を渡すと、thisの参照先がhuman2となっています。

callメソッドとapllyメソッドの違いは、関数に渡す引数の渡し方の違いだけです。

```javascript

func.call("thisに指定するオブジェクト", 引数, 引数, 引数)

//callは、funcに渡す引数を列挙

func.aplly("thisに指定するオブジェクト", [引数, 引数, 引数])

//apllyは配列で渡す。
```
続きはこちら
(【JavaScript】JavaScriptの 「this」とは 2 (thisの問題点と解決策))[https://qiita.com/sho_U/items/e10edd4c6c142fb37ea3]