JavaScriptのthis(コンテキスト)とは？

#this?
this って分かりにくいですよね。
でも、結構単純なんです。

##JavaScriptでのグローバル変数の扱い
this の前にまず先に知っておかないといけない事。
JavaScriptでは、グローバル変数は必ず **何かしら** の所属にあります。
**[何かしら]**.[変数名]=''; ということです。

```js

var aaa = 'A';
console.log( aaa ); // 'A'
console.log( window.aaa ); // 'A'
console.log( aaa === window.aaa ) // true。Node.js の場合は global.aaa
```


グローバルの `var aaa='A';` は `window.aaa='A';` と同じで、
前者は `window.` が省略されている、ということです。
`aaa` から見ると、この **[何かしら]** が **this** になるというだけです。この場合は windows が this になります。

※ 関数内とかの var aaa はまたちょっと別。

##functionで確認
aaa を function にして確認します。

```js
var aaa = function(){ alert(this === window); };
aaa(); // true。window.aaa() と同じなので this は window になる
```
なので、

```js
var o = { x:'XXX', f:function(){ alert(this.x); } };
o.f(); // XXX。this は o になる
```
##色々な方法で確認
```js
var aaa = function(){ alert(this.x); };
var b = { x:'BBB', f:aaa };
var c = { x:'CCC', f:aaa };
b.f(); // BBB
c.f(); // CCC
```
以下のような使い方もできます。

```js
var o = new function(){
  this.x = 'XXX';
  this.f = function(){ alert(this.x); };
};
o.f(); // XXX

var aaa = { x:'XYZ' };
aaa.f = o.f; // ↑ の o.f を代入。
aaa.f(); // XYZ。this が aaa になるので aaa.x が使われる。
```
o.f を aaa.f から呼ぶと this は o ではなく aaa が使われます。
this は付いてく人によって変わっていくんですね。
o.f() なら o だし、aaa.f() だと aaa です。

ただ、`.apply()` や `.call()` ってチンピラみたいのや、`.bind()` というボスのような強力なのもいますので次で。

ちなみに ↑ のコマンド例は良い方法とは思えないです。挙動の確認用として書いたものです。
「友だちの友だちには手を出すな」って誰かが言ってました。プログラムが大きくなるにつれ痛感していきます。

##this の変更( .apply() / .call() )
`.apply()` や `.call()` というものが昔からいました。this を変えられます。
第一引数が this として使われ、この2つの違いは関数に値を渡す方法が違います。

```js
var o = { x:'XXX', f:function(a,b,c){ alert([this.x, a, b, c].join('-')); } };
o.f('A1','B1','C1'); // XXX-A1-B1-C1
o.f.apply({x:'YYY'}, ['A2','B2','C2']); // YYY-A2-B2-C2。※this が変わってる
o.f.call({x:'ZZZ'}, 'A3','B3','C3');    // ZZZ-A3-B3-C3。※ 〃
```

```js
var o = new function(){
  this.x = 'XXX';
  this.f = function(a,b,c){ alert([this.x, a, b, c].join('-')); };
};
o.f('A1','B1','C1');                    // XXX-A1-B1-C1
o.f.apply({x:'YYY'}, ['A2','B2','C2']); // YYY-A2-B2-C2。※this が変わってる
o.f.call({x:'ZZZ'}, 'A3','B3','C3');    // ZZZ-A3-B3-C3。※ 〃
```
呼ばれ方によって、this(コンテキスト) がころころ変わります。
なので、this を固定するために私は以下のようなことをよくやります。

```js
var o = new function(){
  var that = this;
  that.x = 'XXX';
  that.f = function(a,b,c){ alert([that.x, a, b, c].join('-')); };
};
o.f.apply({x:'YYY'}, ['A2','B2','C2']); // XXX-A2-B2-C2
o.f.call({x:'ZZZ'}, 'A3','B3','C3');    // XXX-A3-B3-C3
var f=o.f; f('A4','B4','C4');           // XXX-A4-B4-C4
```
this は変わるので、別の変数に退避してどう呼ばれようといいようにしています。

##this の変更( .bind() )
後から `.bind()` がやってきました。IE9以降です。
こいつを関数に付けて実行すると、this が固定されたその関数が返ってきます。
かなり強力に this を縛り付けます。もう、こいつに this を奪われると奪還は無理です。だぶん。

```js
var o = { x:'XXX', f:function(){ alert(this.x); } };
o.f();                         // XXX
o.f.call({ x:'こら!' });       // こら!
o.f = o.f.bind({ x:'(>_<)' }); // ★ .bind()
o.f();                         // (>_<)
o.f.call({ x:'おーい!' });      // (>_<)
o.f.apply({ x:'戻ってこい!' }); // (>_<)
var f=o.f; f();                // (>_<)
window.f=o.f; window.f();      // (>_<)
```
##this が変わらないアロー関数について
※ ご指摘頂きましたので追記しました。ありがとうございます。

関数定義の方法は **function(){}** と **アロー関数** というやつがあって、これは古いブラウザでは
動かないのですがこの **アロー関数** は上記で書いたような this の考慮は全く要らず、その場の this が引き継がれます。
(この挙動は、はたして分かり易いんだか、分かり難いんだか…)

```js
(function(){
	f1 = ()=>{ console.log(this.x); }; // これが アロー関数 での関数定義。
	f2 = function(){ console.log(this.x); }; // 従来の。
}.call({ x:'XXX'}));

window.x = 'window!';
f1(); // ？
f2(); // ？
window.f1();
```
どうでしょうか？
アロー関数で `f1()` が作成された時点での this は { x:'XXX' } なので `f1()` は 'XXX' になります。
`f2()` はこの場合、window.f2() として動くので this には window が使われ 'window!' となります。
※ f1 も window.f1() として動くけどアロー演算子なので this が違う。

this で最初に？と思うでおなじみの setTimeout の例で書いてみました。

```js
window.x = 'window！';
(function(){
	var that = this;
	
	setTimeout(function(){
		console.log('a', this.x); // a,window!。this は window が使われる。
		console.log('b', that.x); // b,XXX。that はただの変数なので変化しない。
	}, 1000);
	
	setTimeout(()=>{ // アロー関数
		console.log('c', this.x); // c,XXX。this は変わらない。
	}, 2000);
	
}.call({ x:'XXX' }));
```

setTimeout で実行される場合、通常なら `this` は `window` になるのですが、
アロー演算子の場合は ()=>{} がある場所の `this ` をそのまま使うので上記のような動きになります。