thisの挙動や関数スコープのことについて。
実行環境 node v14.2.0
thisの挙動(通常関数)
functionhoge(){console.log(this);}functionfoo(){"use strict";console.log(this);}hoge();//globalオブジェクトが出力foo();//undefinedが出力
ほぼほぼ同じ関数ですが結果が変わってきます。
hoge関数は、globalに紐付けせずに実行してもglobalオブジェクトを参照し出力します。デフォルトでglobalオブジェクトが紐付けされているということです。
しかし、strictモードでは関数がどのオブジェクトにも紐付けされていなければ、この値は未定義になります。したがって、strictモードだとデフォルトでオブジェクトの紐付けは行われないということです。
thisの挙動(アロー関数)
console.log(this);//{} が出力varhoge=()=>{console.log(this);};varbar=()=>{"use strict";console.log(this);};hoge();//{} が出力bar();//{} が出力
ここでの結果は、globalオブジェクトを指すのではなく、関数実行時に内包している親の{}を示しています。
thisの挙動2(アロー関数)
global.name="Taro";lethelloName=()=>{console.log(`hello! ${this.name}`);};letHanako={name:"Hanako",hello:helloName,};helloName();//hello!Hanako.hello();//hello!
@shiracamus様にご指摘、コメントいただいたため、整理、修正中。nodeの場合は上記のように"hello!"しか表示されません。内包している{}が表示されています。
しかし、ブラウザであれば"hello! Taro"と表示されます。つまり、globalオブジェクトのnameが呼び出されていることがわかります。
※ブラウザの場合は1行目のglobalをwindowに変更
thisはいろいろな場合で値が変わるようでややこしいです。
また、thisの挙動からは少し逸れますがこんなこともやってみます。global.nameをvar宣言に変えてみます。
thisの挙動3(アロー関数)
varname="Taro";lethelloName=()=>{console.log(`hello! ${this.name}`);};letHanako={name:"Hanako",hello:helloName,};helloName();//hello!Hanako.hello();//hello!
結果はブラウザ、node共に同じになります。
つまりvarもグローバル変数に値が格納されていることになります。
では次に、if文の中で宣言してみます。
thisの挙動4(アロー関数)
if(true){varname='Taro';}lethelloName=()=>{console.log(`hello! ${this.name}`);};letHanako={name:"Hanako",hello:helloName,};helloName();//hello!Hanako.hello();//hello!
nodeの場合は{}を示しているので何も表示されません。
しかし、ブラウザの場合は同じようにTaroが表示されます。if文の中で宣言してもglobal変数として宣言しているのでnameを使用することができます。
次に、実行する場所によってthisの示す値が異なる挙動をみていきます。
こちらは関数の実行する場所が異なることによる挙動の違いが見れます。
Hanakoの場合はHanakoオブジェクトの中で関数を実行しているのでHanakoが出力されます。
thisの挙動5(アロー関数)
varname="Taro"letdisplayName=function(){console.log(this.name);}lethanako={"name":"Hanako","display":displayName}displayName();// nodeではundefined、 ブラウザはTaroと表示hanako.display();//Hanako
thisの値を制御してみます。
明示的にバインドしてthisが任意の物を指し示すようにします。
thisの挙動6(アロー関数)
varname="Taro"letHanako={"name":"Hanako",}letdisplayName=function(){console.log(this.name);}displayName();//TarodisplayName.apply(Hanako);//HanakodisplayName.call(Hanako);//HanakoletbindDisplayName=displayName.bind(Hanako);//HanakobindDisplayName();
thisの値を制御しました。
結果apply, call, bindDisplayNameで明示的にバインドしたものはHanakoを指し示すようになっています。