Go to list of users who liked
Share on X(Twitter)
Share on Facebook
JavaScriptのthisもこれで完璧!呼び出し方で変わる5つのパターン
こんにちは、とまだです。
JavaScript アドベントカレンダー 2024 のうち、2 日目の記事をお届けします!
私が本格的に現場で JavaScript をはじめたとき、「this を理解したら中級者」と言われました。
それぐらい、this は JavaScript において重要な概念です。
突然ですが、以下のコードの出力結果は分かりますか?
constuser={name:'Alice',greet(){console.log(`こんにちは、${this.name}さん!`);},};constgreet=user.greet;greet();// ???どうでしょうか?
全体として、流れとしてはuser.greet を呼び出しているので、以下のように出力されると思われるかもしれません。
こんにちは、Aliceさん!しかし、実際の出力結果は以下の通りです。
こんにちは、undefinedさん!この結果に驚いた方も多いのではないでしょうか?
実はthis は、どう呼び出すかによって値が変わる曲者なんです。
今回は「JavaScript の this を完全に理解する」ことを目指して、5 つのパターンを解説します!
なぜ this を理解する必要があるの?
JavaScript 経験者なら、このような経験があるかもしれません。
- コードは間違ってないはずなのに
undefinedが出る - React で
this.setStateが動かない - イベントハンドラの中で
thisがundefinedになる
これらの問題は、全てthis の理解が足りないことが多いです。
「this がよく分からない」と感じている方は、ぜひこの記事を読み進めてください!
this の基本:「誰が呼び出したか」が重要
まず、this は「関数を呼び出したもの」を指すと覚えておきましょう。
例えば、以下のようなコードを見てみましょう。
constuser={name:'Alice',greet(){console.log(`こんにちは、${this.name}さん!`);},};// userがgreetを呼び出すuser.greet();// こんにちは、Aliceさん!// グローバルスコープでgreetを呼び出すconstgreet=user.greet;greet();// こんにちは、undefinedさん!同じ関数なのに、呼び出し方によって結果が変わってしまいます。
なぜこうなるのか、5 つのパターンを見ながら理解していきましょう。
this の 5 つの顔
1. メソッド呼び出し:オブジェクトのメソッドとして呼ぶ場合
オブジェクトのメソッドとして呼び出す場合、this はそのオブジェクトを指します。
constuser={name:'Alice',greet(){console.log(`こんにちは、${this.name}さん!`);},};user.greet();// こんにちは、Aliceさん!この場合、関数を呼び出したのはuser オブジェクトなので、this はuser を指します。
2. 普通の関数呼び出し:単独で呼び出す場合
普通の関数として呼び出す場合、this はundefined(strict モード)またはwindow(非 strict モード)を指します。
functionstandalone(){console.log(this);}standalone();// undefined または windowこれは意図しない動作の原因になりやすいので、気をつけましょう。
3. アロー関数:外側の this をそのまま使う
アロー関数のthis は、関数が定義された場所のthis を引き継ぎます。
もう少し正確に言うと、アロー関数はthis を持たず、外側のthis をそのまま使います。
constuser={name:'Alice',// 通常の関数greet(){constarrow=()=>{console.log(`こんにちは、${this.name}さん!`);};arrow();},};user.greet();// こんにちは、Aliceさん!アロー関数はthis を持たず、外側のthis をそのまま使うので、コールバック関数でよく使われます。
4. new による呼び出し:新しいオブジェクトを指す
new で関数を呼び出すと、this は新しく作られたオブジェクトを指します。
functionUser(name){this.name=name;}constalice=newUser('Alice');console.log(alice.name);// Aliceこれは、JavaScript のクラス構文の内部でも使われています。
5. bind/call/apply による呼び出し:this を固定する
bind、call、apply メソッドを使うと、this の値を明示的に指定できます。
constuser={name:'Alice',greet(){console.log(`こんにちは、${this.name}さん!`);},};constgreet=user.greet.bind(user);greet();// こんにちは、Aliceさん!この方法は、イベントハンドラなどでthis の値を固定したい場合によく使われます。
実践的な使い方:よくあるバグと解決策
イベントハンドラでの問題
最もよく遭遇するthis のバグは、イベントハンドラでの問題です。
constbutton=document.querySelector('button');constuser={name:'Alice',handleClick(){console.log(`${this.name}がクリックしました!`);},};// 🙅♂️ ダメな例:thisがundefinedになるbutton.addEventListener('click',user.handleClick);// 🙆♂️ 良い例1:bindを使うbutton.addEventListener('click',user.handleClick.bind(user));// 🙆♂️ 良い例2:アロー関数でラップするbutton.addEventListener('click',()=>user.handleClick());イベントハンドラ内でthis を使いたい場合は、bind やアロー関数を使ってthis の値を固定しましょう。
React での this の問題
React でクラスコンポーネントを使う場合も、this の問題に遭遇することがあります。
classButtonextendsReact.Component{// 🙅♂️ ダメな例:thisがundefinedになるhandleClick(){this.setState({clicked:true});}// 🙆♂️ 良い例1:メソッドをアロー関数で定義handleClick=()=>{this.setState({clicked:true});};render(){// 🙆♂️ 良い例2:bindを使うreturn<buttononClick={this.handleClick.bind(this)}>Clickme!</button>;}}ここでも、bind やアロー関数を使ってthis の値を固定することで問題を解決できます。
最近の React では関数コンポーネントと Hooks を使うことが推奨されており、その場合は this の問題を気にする必要はありません。
まとめ
今回説明した内容を整理すると、以下のようになります。
thisは「関数を呼び出したもの」を指す- 呼び出し方によって
thisの値が変わる - 5 つのパターンを覚えておく
- メソッド呼び出し
- 普通の関数呼び出し
- アロー関数
- new による呼び出し
- bind/call/apply による呼び出し
覚えるのが大変そうに見えますが、基本的な考え方さえ理解できれば、あとは実践の中で自然と身についていきます。
最後まで読んでいただき、ありがとうございました!
他にもアドベントカレンダー記事を書いています!
他にも、2024 年のアドベントカレンダーに参加しています。
以下の記事でまとめているので、よければ他の記事も読んでいただけると嬉しいです!
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme
