Javascriptのthisまとめ
はじめに
JavaScriptを触ってるけど、thisの使い方は特に意識しないでやってきた。
thisの挙動が複雑だとか4種類あるとかは聞いたことあったけど、
その問題に直面することがなかったから無視してたというのが本音。
天からthisから逃げるなと言われてる気がしたので、いい加減に調べてまとめることにする。
this4種
JavaScriptのthisは以下の4つ。
それぞれについて簡単な例とともにまとめる。
- 関数(function)呼び出しパターン
- メソッド呼び出しパターン
- コンストラクタパターン
- apply,bind,callパターン
関数(function)呼び出しパターン
関数を呼ぶ際のthisは基本的にはglobalオブジェクトを指す。
ただし、use strict
を指定しているとundefinedになる。
// 'use strict'なしパターン function test() { console.log(this); } test(); // Window{...}
// 'use strict'ありパターン 'use strict' function test() { console.log(this); } test(); // undefined
メソッド呼び出しパターン
関数もメソッドも同じだろって感じだけど実は違う。 下記のようなパターンのこと。
const obj = { test: function() { console.log(this); } } obj.test(); // { test: [Function: test] }
ちなみにこのthisをどうしてもglobalとして使いたいなら下記のようにする。
const obj = { test: function() { console.log(this); } } // 下記パターンどちらでもglobalになる // パターン1 const globalThis = obj.test; globalThis(); // Window{...} // パターン2 (0, obj.test)(); // Window{...}
コンストラクタパターン
コンストラクタのthisは生成するobject(自分自身)を指すようになる。
何言ってるかわからなくても、見ればなんとなくわかるはず。
class Test { constructor(value){ this.value = value; // 自身(Test)のvalueに引数のvalueを入れてる } } const newClass = new Test(10); console.log(newClass.value); // 自身のvalueにちゃんと入っている
ちょっと古いクラスの書き方するなら下のような感じ。
もちろん結果は同じ。
ただしこの書き方だと、あくまで関数なのでnew
を忘れるとthisはglobalを指すようになってしまう。
おとなしくclass
と付けるのがいいと思う。
function Test(value) { this.value = value; } const newClass = new Test(10); console.log(newClass.value);
apply,bind,callパターン
apply,call
applyとcallは共にthisの内容を設定できるようにするもの。
下記のようなパターンのこと。
function test() { console.log(this); } const obj = { name: 'test' }; test(); // testのthisをobjに設定 test.call(obj); // obj{...} test.apply(obj); // obj{...}
applyとcallの違いは引数のとり方が違う。
applyは配列、callはそのままといった具合。
const testObj = { test: function(value1, value2) { console.log('this:', this); console.log('value1:', value1); console.log('value2:', value2); } } const obj = { name: 'test' }; testObj.test.apply(obj, [1, 3]); testObj.test.call(obj, 1, 3);
# 実行結果 this: { name: 'test' } value1: 1 value2: 3 this: { name: 'test' } value1: 1 value2: 3
bind
ここで参照するthisはこれじゃなきゃ嫌なんだ!という時に使う。
要は強制的にthisの内容を紐付けてやること。
function test() { console.log(this); } const obj = { name: 'test' }; // testのthisをobjにする const bid = test.bind(obj); test(); // こっちはglobal参照 bind(); // こっちはobj参照
おまけ(アロー関数)
アロー関数はthisを変えたりしない。
変に値が変わらない分わかりやすいかも知れない。
const obj = { func: function(){ console.log(this); }, arrow: () => { console.log(this); } } obj.func(); // { func: [Function: func], arrow: [Function: arrow] } obj.arrow(); // Windw{...}
まとめ
ようやく向き合ったthis
は思ってたよりも理解不能じゃなかった。
理解不能ではなかったけど、わかりやすく説明するのは無理だなって思った。
今度はprototype辺りとも向き合いたい。