はじめに
普段C#で開発を行っていますが、最近Web開発技術も勉強中です。
その中で、Javascriptのthisで混乱したことがあったので整理します。
Javascriptのthis
例えば、ブラウザのコンソールで以下のコードを書きます。
let user = {
firstName: "John",
sayHi: function(){
console.log( this.firstName )
}
};
この場合、user.sayHi()を実行すると、コンソールで"John"を表示できます。
今度は以下のようにアロー関数内でthisを使ってみます。
let user = {
firstName: "John",
func: () => console.log(this.firstName)
};
この場合、user.func()を呼んでもコンソールで"undefined"が表示されました。
thisを確かめるため、以下のコードに書き換えました。
let user = {
firstName: "John",
func: () => console.log(this)
};
上記を試すと、コンソールにWindowが表示されました。
アロー関数の場合、thisはWindowを指しますが、WindowはfirstNameを持っていないため、undefinedとなるようです。
function()を使用する場合と、アロー関数を使用する場合で、thisの指し先が異なっています。
MDNには以下の記載がありました。(MDNの該当箇所はこちら)
ほとんどの場合、this の値はどのように関数が呼ばれたかによって決定されます (実行時結合)。これは実行時に代入によって設定することはできず、関数が呼び出されるたびに異なる可能性があります。
アロー関数の場合、MDNには以下の記載がありました。(MDNの該当箇所はこちら)
アロー関数では、this はそれを囲む構文上のコンテキストの this の値が設定されます。グローバルコードでは、グローバルオブジェクトが設定されます。
function()の場合は実行時にthisを決定し、アロー関数の場合は、呼ばれ方に寄らず、常に定義した場所でのthisを参照するという解釈をしました。
実行時の呼ばれ方というのをもう少し詳しく見るため、以下のようなコードを書いた場合を考えます。
let user = { firstName: "John" };
let admin = { firstName: "Admin" };
function sayHi() {
console.log( firstName.name );
}
user.f = sayHi;
admin.f = sayHi;
sayHi(); // "undefined"が表示される
user.f(); // "John"が表示される
admin.f(); // "Admin"が表示される
どのオブジェクトから呼ばれているかによってthisが変わるということのようです。
オブジェクトに設定せず、コンソール上でただsayHi()を呼ぶ場合、呼び出しているオブジェクトがグローバルコンテキスト(ブラウザ上だとWindow)になり、グローバルでfirstNameプロパティを設定していないため、undefinedとなります。
気になったので以下の場合を試しました。
let user = {
firstName: "John",
func: () => alert(this.firstName),
sayHi: function(){
this.func();
}
};
user.sayHi(); // alertで"undefined"が表示される
function()の中のthisはuserを指せているため、alertの表示自体は出ますが、アロー関数のthisは定義時のthisを参照する、つまり、今回の場合はグローバルオブジェクトのWindowを指します。
グローバルオブジェクトでは特にnameプロパティを定義していないため、undefinedが表示されました。
さいごに
thisの扱い方、ややこしかったですが、いろいろ試して整理できました。