Core JavaScript 3.this (2)

この記事はweb開発に欠かせないJavaScriptのコアな概念をしっかり理解しようということでCore Javascript(韓国語)を要約した内容になります。

3. this

目次

状況によって変わるthis

コールバック関数呼び出す時のthis

setTimeout(function () {
  console.log(this); // (1) windowが出力される
  }, 300);

[1,2,3,4,5].forEach(function (x) {
  console.log(this, x); // {2} windowが5回出力される
});

document.body.innerHTML += '<button id="hoge">Click!</button>';
document.body.querySelector('#hoge').addEventListener('click', function (e) {
  console.log(this, e); // {3} buttonエレメントとMouseEventが出力される
});

addEventListenerは呼び出し元をthisとして指定すように定義されていて、グローバルオブジェクトのwindowでなくbuttonエレメントが出力される。

コンストラクタ内部のthis

var User = function (name, age) {
  this.shopName = this.name + '\'s shop';
  this.name = name;
  this.age = age;
}
var naitoh = new User('Naitoh Tetsuya', 38);
var ibushi = new User('Ibushi Kota', 38);

console.log(naitoh, ibushi);
/ *
  User { shopName: 'Naitoh Tetsuya's home', name: Naitoh Tetsuya, age: 38 }
  User { shopName: 'Ibushi Kota's home', name: Ibushi Kota, age: 38 }
* /

thisをbindする方法

self = thisなどで回避するのではなく、call, apply, bindを使って簡潔にthisを引き渡すことができる。

束縛(する)、拘束(する)、結びつける、関連付ける、などの意味を持つ英単語。ITの分野では、何らかの要素やデータ、ファイルなどが相互に関連付けられている状態や、そのような状態を実現する機能などのことを指すことが多い。

thisは基本状況によって変わるが、直接バインドすることもできる。

callメソッド

var func = function (a, b) {
  console.log(this, a, b);
};

func(1, 2); // window 1 2
func.call({x: 3}, 1, 2); // {x: 3} 1 2

applyメソッド

callメソッドと機能的に同一。第2引数として配列を受け取る。

var func = function (a, b) {
  console.log(this, a, b);
};

func.apply({x: 3}, [1, 2]); // {x: 3} 1 2

bindメソッド

ES5から追加されたメソッド。 引き渡されたthisと引数で新しい関数を返す。

var func = function (a, b, c, d) {
  console.log(this, a, b, c, d);
};

func(1, 2, 3, 4); // window 1 2 3 4

var bindFunc1 = func.bind({x: 1});
bindFunc1(5, 6, 7, 8); // {x: 1} 5 6 7 8

var bindFunc2 = func.bind({x: 1}, 4, 5);
bindFunc2(6, 7); // {x: 1} 4 5 6 7
bindFunc2(8, 9); // {x: 1} 4 5 8 9

name プロパーティ

bindメソッドで作った関数にはboundというbindの受動態がプレフィックスとして付く。 callとapplyよりデバッグしやすい。

var func = function (a, b, c, d) {
  console.log(this, a, b, c, d);
};

var bindFunc = func.bind({ x: 1 }, 4, 5);
console.log(func.name);     // func
console.log(bindFunc.name); // bound func

アロー関数の例外事項

アロー関数は実行コンテキスト生成時thisをバインドしないので、アロー関数の内部にはthisが存在しない。 thisを参照するとスコープチェーン上一番近いthisを参照することになる。

var obj = {
  outer: function() {
    var innerFunc = () => {
      console.log(this);
    };
    innerFunc();
  }
};
obj.outer(); // obj

call, apply, bindも使わずにthisを参照することができてさらに簡潔になる。

まとめ

参考文献