#まえがき
おはようございます。Make IT アドベントカレンダーの5日目を担当しますバンドリが好きなhaduki1208です。
明日は @yamato3310 さんが投稿してくださいます。
明後日はライブを見に現地へ行きます。
本日の内容はJavaScriptのアロー関数の束縛の意味について自分の考えを述べます。
#thisを束縛しない?
MDN アロー関数 2018年12月04日現在
アロー関数式 は、その名のとおり矢印を使って記述し、function 式より短い構文で同様な内容を記述することができます。なおthis, arguments, super, new.target を束縛しません。また、アロー関数式は、メソッドでない関数に最適で、コンストラクタとして使うことはできません。
先日、後輩にアロー関数について質問されました。
「アロー関数はthisを束縛しない」とはどんな意味でしょうか。
僕も初めてアロー関数について学んだ際は「束縛」の意味が理解できませんでした。
今回は個人的な解釈のもと(言語仕様書をkwskは読んでないため)説明します。
※strictモードについては触れません
#束縛しないとは、強制的な値の代入を行わないということ
以下はthisの値が変わる例です。
const Human = function (name) {
console.log(this); // (1) Human
this.name = name;
this.sayName = function () {
console.log(this); // (2) Human
console.log(`I am ${this.name}.`);
}
this.sayNameLater = function (time) {
setTimeout(function () {
console.log(this); // (3) window
console.log(`I am ${this.name}.`);
}, time);
}
}
const taro = new Human("taro");
taro.sayName();
taro.sayNameLater(1000);
(1)と(2)のthisにはHumanオブジェクトが入ります。
しかし、(3)にはwindowオブジェクトが入ります
(1)はコンストラクタ(new)に呼び出されたため、thisにはHumanが代入されました。
(2)はHumanオブジェクトのインスタンスに呼び出されたため、thisにはHumanが代入されました。
(3)はグローバルから関数として呼び出されたため、thisにはwindowが代入されました。
このようにthisは呼び出し元によって値が変動します。
関数オブジェクトの呼び出し方によって定められた値が、強制的にthisに代入されるためです。
アロー関数はこの強制的な代入を行わないようにします。
まとめ
「thisを束縛する」 === 「thisに強制的に値を代入する」
「thisを束縛しない」 === 「thisに強制的に値を代入をしない」
#外のスコープのthisを参照する
アロー関数を使用する場合、thisに値は代入されません。
const taro = {
name: "taro",
sayName: () => {
console.log(`I am ${this.name}.`);
}
};
taro.sayName();
console.log(this); // window
「sayNameメソッドをアロー関数で定義した場合、thisには何も入らないからundefinedでエラーが起きる!」
って訳ではないです。外のスコープにthisがないか探してくれます。
これはグローバル領域のthis(windowオブジェクト)を参照します。
※functionを全部アロー関数に置き換えてやるぜ!って時に上のような書き方をしてバグらせてました。
const Human = function(name){
this.name = name;
this.sayName = () => {
console.log(this.name);
};
}
const taro = new Human("taro");
taro.sayName();
これは太郎君が名前をしゃべってくれます。
アロー関数の外のスコープ(Humanスコープ)は、コンストラクタによってthisにHumanが代入されているためです。
#アロー関数をコンストラクタに使用できない訳
const Human = name => {
this.name = name;
this.sayName = () => {
console.log(this.name);
};
}
const taro = new Human("taro");
「Human is not a constructor.」と怒られました。
アロー関数はthisに値を代入しないので、thisにHumanが強制的に代入されません。
thisがwindowオブジェクトのためコンストラクタの役割が成立しないからです。
#あとがき
MDNで「束縛する」「束縛しない」のキーワードはころころ変わってしまっているそうで、
アロー関数を勉強した時期によって様々な見解がありそうです。
この「thisに強制的に値を代入しない」という考え方でアロー関数に理解を深めていただけたのであれば幸いです。