JavaScriptを勉強していて頻繁に出てくるのがこの「this」だが、
定義する場所によって参照先が違ったりと色々厄介なやつなので勉強がてら調べて見た。
(挙動の確認のためあえてvarを使ってるが基本使わないほうがいい)
関数からの呼び出しの場合
var test = 'nogi';
function myThis(){
console.log(this); // Window
this.test = 'hoge';
}
myThis();
console.log(test); // hoge
関数から呼び出したthisはグローバルオブジェクト
を参照していることがわかる。
つまり、グローバル変数のtestに'hoge'を入れたことで'nogi'が変わってしまった(グローバル汚染)
ただし、ES6から変数の定義にletやconstが使えるようになったので特に気にしなくて問題はなさそう。
let test = 'nogi';
function myThis(){
console.log(this); // Window
this.test = 'hoge';
}
myThis();
console.log(test); // nogi
メソッドからの呼び出しの場合
var test = 'yamada';
var myobj = {
test: 'taro',
myThis: function(){
console.log(this); // {test: "taro", myThis: ƒ}
this.test = 'hanako';
}
};
myobj.myThis();
console.log(myobj.test); // hanako
console.log(test); // yamada
メソッドから呼び出したthisは属してるオブジェクト
を参照していることがわかる。
当然グローバルスコープへの影響もない。
var test = 'yamada';
var myobj = {
test: 'taro',
myThis: function(){
console.log(this);
this.test = 'hanako';
function myThis2(){
console.log(this.test); // yamada
}
myThis2();
}
};
myobj.myThis();
メソッド内に関数myThis2を追加した場合の挙動。
メソッドで定義しているが、あくまで関数なので参照先はグローバルスコープ
になっている。
クラスからの呼び出しの場合
var test = 'yamada';
class myClass{
constructor(){
this.test = 'taro';
console.log(this); // myClass {test: "taro"}
}
myThis(){
console.log(this); // myClass {test: "taro"}
}
}
var myobj = new myClass();
myobj.myThis();
console.log(test); // yamada
クラスで呼び出したthisはプロパティもメソッドも属しているクラス
を参照していることがわかる。
この辺はシンプルでわかりやすい。
class myClass{
constructor(){
this.test = 'taro';
console.log(this);
}
myThis(){
console.log(this);
function myThis2(){
console.log(this); // undefined
}
myThis2();
}
}
var myobj = new myClass();
myobj.myThis();
クラス内のメソッド内に関数myThis2を定義した。
何と、thisの参照先がundefined
になってしまった!
詳しいことは今度調べてみよう。。
アロー関数からの呼び出しの場合
var test = 'yamada';
var myobj = {
test: 'taro',
myThis: function(){
this.test = 'hanako';
var arrow1 = function (){
console.log(this.test); // yamada
}
var arrow2 = () =>{
console.log(this.test); // hanako
}
arrow1();
arrow2();
}
};
myobj.myThis();
先ほどのメソッド内に定義されている関数のスコープを確認した時のものにアロー関数を追加したもの。
arrow1は前記した通り、関数なのでグローバルオブジェクト
を参照しているが、何とアロー関数の場合はメソッドを呼び出しているオブジェクト
を参照している。
同じ関数でも参照先が違うのは注意しておきたい。