アロー関数で this を操る 🪄
はじめに
JavaScript の this、混乱したことありませんか?
「呼び出し方で変わる」「イベントで指すものが違う」──誰もが一度はハマるポイントです。
でも、Arrow Function(アロー関数)を使うと this の挙動が一気にわかりやすくなります。
この記事では、「なぜ Arrow Function では this が変わらないのか?」を ES5の関数型の書き方で解説します。
※
class構文は使いません。すべて関数とオブジェクトリテラルでいきます!
Arrow Function はただの省略記法じゃない
const greet = (name) => {
console.log(`Hello, ${name}!`);
};
見た目は短く書けるだけに見えますが、実は this の仕組みがまったく違う のがポイントです。
Arrow Function は自分自身の this を持たず、定義されたときのスコープ(外側)にある this
をそのまま使うようになっています。
this は「呼び出し時」ではなく「定義時」に決まる
普通の関数は、呼び出し方によって this が変わります。
たとえばオブジェクトから呼ぶとそのオブジェクトが、単独で呼ぶと window(または undefined)になります。
でも Arrow Function は違います。
定義されたときにすでに this が固定されるんです(=レキシカルスコープ)。
実例①:オブジェクト内の this が取れない!?
const user = {
name: "Alice",
greet: () => {
console.log(`Hello, ${this.name}`);
},
};
user.greet(); // Hello, undefined
このコード、user.greet() と呼んでいるのに this.name が取れません。
なぜかというと、greet は Arrow Function なので、外側(グローバル)の this を参照してしまうからです。
💡 オブジェクトのメソッドに Arrow Function を使うのは NG!
thisはそのオブジェクトを指しません。
実例②:コールバック関数では救世主になる
では、Arrow Function が 便利に働く ケースを見てみましょう。
const counter = {
count: 0,
start: function () {
setInterval(() => {
this.count++;
console.log(this.count);
}, 1000);
},
};
counter.start();
setInterval の中で Arrow Function を使っています。
普通の関数だと this は window を指してしまいますが、Arrow Function は外側(ここでは start メソッド)の this を引き継ぎます。
つまり、this.count は正しく counter.count になります。
実例③:関数コンストラクタでも this が保たれる
ES5 風にコンストラクタ関数を書いた場合も、Arrow Function のレキシカル this はとても役立ちます。
function Timer() {
this.seconds = 0;
setInterval(() => {
this.seconds++;
console.log(this.seconds);
}, 1000);
}
const t = new Timer();
setInterval の中の this は、ちゃんと Timer インスタンスを指します。
これを普通の関数で書くと、this が window に変わってしまいます。
昔は bind(this) で頑張っていた
ES5 の頃は、コールバック内で this を保つために、よく .bind(this) や var self = this; を使っていましたよね。
function Timer() {
this.seconds = 0;
var self = this;
setInterval(function () {
self.seconds++;
console.log(self.seconds);
}, 1000);
}
あるいはこう。
function Timer() {
this.seconds = 0;
setInterval(function () {
this.seconds++;
}.bind(this), 1000);
}
でも、Arrow Function が登場してからはこの面倒な手間が不要になりました。
自然に外側の this をキャプチャしてくれるんです。
"this を閉じ込める"という感覚
Arrow Function は「自分の this を持たず、外側の this を閉じ込める(キャプチャする)」仕組みです。
そのため、コールバック関数や非同期処理でも this がブレません。
function App() {
this.message = "Hello from App!";
document.body.addEventListener("click", () => {
console.log(this.message);
});
}
const app = new App();
// クリックすると "Hello from App!"
イベントハンドラの中でも、this は常に App インスタンスを指します。
これが Arrow Function の大きな強みです。
注意: オブジェクトのメソッドには向かない
オブジェクトのメソッドには Arrow Function を使わないほうがいいです。
const obj = {
value: 123,
show: () => {
console.log(this.value);
},
};
obj.show(); // undefined
Arrow Function の this は「外側」から取ってくるため、オブジェクトそのものを指すことができません。
→ メソッドは普通の function
記法(または短縮メソッド構文)で定義するのがベターです。
まとめ
Arrow Function の最大の特徴は「this を定義時に固定する」こと。
これにより、
- コールバック内で this が変わらない\
- bind や self = this が不要になる\
- 非同期処理やイベントリスナーで扱いやすい
ただし、
- オブジェクトメソッドには不向き(this が外に逃げる)
という点に注意すれば、Arrow Function は非常に強力なツールです。
Happy Lexical Scoping! ☕️
「this が変わらない」だけで、JavaScript がぐっと楽になります。
Discussion