この記事は ウェブクルー Advent Calendar 2022 6日目の記事です。
昨日は @wc-takaharaさんの「TanStack Query(旧React Query)について整理してみた」でした。
はじめに
WebCrewバックエンドエンジニア一年目の@kouki_kubotaです。
最近業務で調べる機会があったので、今さら感はありますがJSのthisについて書いてみようと思います。
関数呼び出し
これは使う機会が多いのでわかりやすい例だと思います。
簡単に書くと以下のようになります。
function example() {
console.log(this)
}
example(); //Window
この場合、exampleはグローバルオブジェクトなのでブラウザで表示した場合windowオブジェクトを表示します。
対して、strictモードだと以下のようになります。
"use strict"
function example() {
console.log(this)
}
example(); //undefined
strictモードというのはバグになりそうだけど通常エラーになっていなかったコードに対しエラーを表示させる仕組みのことです。
※詳しくは以下
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Strict_mode
この場合、example()
はundefined
を返します。
メソッドチェーン
const employee = {
name: 'kubota',
age: 22,
getName: function() {
return this;
},
getAge: function() {
return this;
}
}
console.log(employee.getName().getAge()); //{name: 'kubota', age: 22, getName: ƒ, getAge: ƒ}
自作でメソッドチェーンを作る際にはthisを戻す必要があります。
上の結果から分かるように、戻り値thisはオブジェクト自身を指すので、メソッドの呼び出しが可能です。
アロー関数
アロー関数というのは
let fruit = (apple) => { return this };
みたいなやつです。省略記法もいろいろあるので詳しくは以下からどうぞ。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions
アロー関数は先ほどまでとは異なるthisの挙動をします。
アロー関数のthisの挙動はよく束縛されると表現されます。
簡単に言うとアロー関数のthisは関数定義の段階で決まっているということです。
以下比べてみます。
//通常の関数宣言の場合
this.fruit = 'apple';
function selectFruit() {
console.log(this.fruit);
}
const object = {
fruit: 'banana',
func: selectFruit
}
object.func(); //banana
//アロー関数の場合
this.fruit = 'apple';
let selectFruit = () => {
console.log(this.fruit);
}
const object = {
fruit: 'banana',
func: selectFruit
}
object.func(); //apple
このように通常の関数宣言だとオブジェクトを参照するためthisの値は常に一定ではありません。(関数宣言の時点でthisの値が確定しない)
対して、アロー関数の場合は関数宣言をした時点でthisの値が確定します。
また、上の例からもわかるようにアロー関数のthisは自身が定義されているスコープを参照するthisを確立するため、アロー関数内にthisは持ちません。よってメソッドチェーンは使えません。
コンストラクタ
次にコンストラクタです、他のオブジェクト指向言語のコンストラクタと似ているようで異なる挙動がたくさんあります。
そもそもJSはプロトタイプベースの言語なので、JavaなどのようなClassは本来ありません(ES6以降クラス構文が出ていますが、似て非なるものです)
実際に見てみます。
function Employee(name) {
this.name = name;
this.getName = function() {
return this.name;
};
}
let employee = new Employee('kubota');
console.log(employee.getName()); //kubota
このようになります。thisはnewによって新しく作られたemployeeオブジェクトを参照します。
また、先ほどのアロー関数はコンストラクタとして使用することはできません。
bind, call, apply
bindは強制的にオブジェクトを紐づけることができます。
function Fruit() {
console.log(this)
}
let obj = { name: "apple" }
let bindFruit = Fruit.bind(obj)
bindFruit() // => {name: "apple"}
call/applyはbindの逆のイメージで、呼び出し側からオブジェクトを紐づけます。
function Fruit() {
console.log(this)
}
let obj = { name: "apple" }
Fruit.call(obj) // => {name: "obj"}
おわりに
以上です、簡単にはなりますがJSのthisについて思いつく限りあげてみました。
間違い等ありましたらコメントでご教授ください。
明日は、@komacchi_uさんになります。
よろしくお願いします!