JavaScript中this指向問題終結篇
前言
Javascript 中的 this 關鍵字總是指向一個對象,這個對象是根據函數運行時的環境而定的,總結下來也不外乎以下六種情況。
一、在JS代碼的最外層
在JS代碼的最外層,this指向window對象
var name = "光頭纔是最強";
console.log(this);
console.log(this.name);
二、作爲對象的方法調用
當函數是作爲對象的屬性調用時,this指向這個對象
var name = '什麼是最強';
var obj = {
name: '光頭纔是最強',
getName: function() {
console.log(this.name);
}
}
obj.getName();
三、作爲普通函數調用
當函數是作爲普通函數調用時,this指向window
var name = '什麼是最強';
var getName = function() {
var name = '光頭纔是最強';
console.log(this);
console.log(this.name);
}
getName();
console.log(this);
console.log(this.name);
四、構造器調用
當函數被當作構造器來創建對象時,函數中的this指向創建出來的對象
var name = "什麼是最強"
var myClass = function() {
this.name = "光頭纔是最強";
};
var classA = new myClass();
console.log(classA.name);
當函數作爲構造器被調用時,有一種情況要注意,就是如果函數返回了一個對象,那麼this的指向就會指向這個被返回的對象,而不是用構造器 new 出來的對象
var name = "什麼是最強"
var myClass = function() {
this.name = "光頭纔是最強";
return {
name: "沒想到吧"
}
};
var classA = new myClass();
console.log(classA.name); //函數返回一個對象,this會指向這個被返回的對象
五、Function.prototype.call 或 Function.prototype.apply 調用
有用過 call 和 apply 的同學都知道這兩個方法可以改變函數的this指向(沒了解過或不熟練的同學一定要認真學)
var name = "什麼是最強"
var obj1 = {
name: "熊大"
}
var obj2 = {
name: "光頭纔是最強",
getName: function() {
return this.name;
}
};
console.log(obj2.getName.call(obj1)); //用call將原本指向obj2的this,改成指向obj1
六、箭頭函數中的this
在ES6中允許使用 => 來定義函數,這種函數叫做箭頭函數,他本身沒有this,他的this是從定義時環境的this引用而來的
var name = '沒想到吧';
var obj = {
name: "光頭纔是最強",
getNameSimple: function() {
return this.name;
},
getNameArrow: () => {
return this.name;
}
}
console.log(obj.getNameSimple()); //普通函數 getNameSimple 作爲對象屬性調用,this指向對象
console.log(obj.getNameArrow()); //箭頭函數 getNameArrow 的this引用定義時環境的this,
//getNameArrow定義時環境的this是window
普通函數的this是可以動態改變的,而箭頭函數的this是固定的,在定義時引用環境中的this後將無法改變
var name = '光頭纔是最強';
var myClass = function() {
this.name = "沒想到吧";
this.arrowFn = () => {
console.log(this.name);
};
};
var classA = new myClass();
var fn = classA.arrowFn;
fn(); //用普通函數調用的方式調用arrowFn,理論上此時this應該指向window,但由打印結果
//可知this是指向了arrowFn定義時的this,說明箭頭函數的this確實不會改變
由於箭頭函數的this是固定不變的,所以在箭頭函數上使用call、apply方法將無法改變this指向
var name = "沒想到吧";
var obj1 = {
name: "光頭纔是最強"
}
var obj2 = {
name: "什麼是最強",
getNameSimple: function() {
return this.name;
},
getNameArrow: () => {
return this.name;
}
}
console.log(obj2.getNameSimple()); //普通函數作爲對象屬性調用,this指向對象
console.log(obj2.getNameSimple.call(obj1)); //普通函數this指向可變,用call改變普通函數this指向有效
console.log(obj2.getNameArrow()); //箭頭函數定義時環境中的this指向window,所以箭頭函數this指向window
console.log(obj2.getNameArrow.call(obj1)); //箭頭函數this指向不可變,用call改變箭頭函數this指向無效