this是什麼
this是一個關鍵字,指向調用該方法的對象。
this是在執行環境上下文中被指定好的,也就是在一個函數調用但是還沒有開始執行的時候設定好的。它和作用域在函數聲明的時候公共部分就設定好了不一樣,它是看,當這個函數作爲某個對象的方法調用時,誰調用了它,它就指誰。它取決於誰調用了它
在js權威指南中,函數的調用分爲四種情況:
- 作爲函數
- 作爲方法
- 作爲構造函數
- 通過它們的apply和call方法調用
純粹的函數調用
這種純粹的函數調用,通常指的環境是全局,this指向的是window(非嚴格模式),或者undefined(嚴格模式)。以下寫的都是非嚴格模式下的結果:
和變量不同,關鍵字this沒有作用域的限制,嵌套的函數不會從調用它的函數中繼承this,如果嵌套函數作爲函數調用,其this值不是全局對象就是undefined。
var a = 0;
function test() {
alert(this.a);//0
}
test();
function test,雖然實際上是作爲了window這個對象的一個方法,相當於window.test();
function test() {
var func = function add(){
alert(this);//window
};
func();
}
test();
函數add賦值給了func,此時的func也是函數類型,內容也就是賦值=後那一串。
func();其實也就是(function add(){
alert(this);//window
})();
所以這裏,還是通過通過的函數調用,所以這裏的this也仍然是window。
在https://www.ibm.com/developerworks/cn/web/1207_wangqf_jsthis/index.html
中看到這個例子也是類似的,也想了一會才明白:
var point = {
x : 0,
y : 0,
moveTo : function(x, y) { //這個函數是作爲moveTo的方法而被調用的,this指向moveTo
// 內部函數
var moveX = function(x) { //這個函數是和上面的add相似,都是相當於是在全局下定義的,沒有作爲其他對象的方法,所以下面這兩個this指向的是全局。
this.x = x;//this 綁定到了哪裏?
};
// 內部函數
var moveY = function(y) {
this.y = y;//this 綁定到了哪裏?
};
moveX(x);
moveY(y);
}
};
point.moveTo(1, 1); //調用函數moveTo
point.x; //==>0
point.y; //==>0
x; //==>1
y; //==>1
這時候如果不希望這兩個moveX,moveY的this指向全局,可以使用that,詳細見上述地址。
作爲方法調用
下面又是另一種情況,函數做爲了其他對象的方法來調用:
var test = {
a:0,
b: {
c:7,
fn:function(){
alert(this.c);//7
}
}
};
window.test.b.fn();
那麼,這個時候又有一個問題,調用的對象又是指向誰呢?是window,還是test,還是b。
在函數中,彈出c的值是7,證明this訪問的是b中的內容,所以調用函數的對象它設定的是b。
註釋掉c:7,會發現會彈出undefined。
個人看到很多博客後得出一個結論:作爲方法調用時,它的this指向的是調用它的最近的那一個對象。
作爲構造函數
如果函數或者方法調用之前帶有new關鍵字,它就構成構造函數調用
先了解一下new這個關鍵字來調用構造函數會發生什麼實際的步驟:
1)創建一個新對象
2)將構造函數的作用域賦給新對象(因此this就指向了這個新對象)
3)執行構造函數中的代碼(爲這個新對象添加屬性)
4)返回新對象
先分析一下底下這個new:
function Person() {
this.name = "zhuyi";
}
var a = new person();//沒有參數的話其實這對括號可以省略
alert(a.name);//zhuyi
1)創建了一個新的空對象,比方我給這個空對象取名叫tmp(這個名字不存在,只是爲了便於看…)
2)將Person的作用域賦給tmp,也就是把this指向了tmp
3)執行Person中的代碼,這裏就是給tmp添加了name屬性
4)返回這個對象,然後這裏賦給了a
於是最後這一系列過程後,a就有了name屬性,也能alert出來了。
apply和call的調用
這兩個方法都能顯式指定this的值。
apply和call這兩個方法的第一個參數就代表着這個函數會被哪個對象來調用。那麼這個this就會被指定成這個對象。
var o = {};
function person() {
this.name = "zhuyi";
}
// person.call(o);
// person.apply(o);
alert(o.name);//undefined
新建了個空對象o,想用person作爲對象o的方法來調用,這時候,使用call和apply都可以做到,將對象o當成他們的第一個參數傳入,這時候,person就是o的一個方法,此時這個person函數的this都被設定爲指向o,那麼o.name也自然能返回設定的值了。
當apply和call的第一個參數設置爲空,此時,this指向全局
var o = {};
var name = "L";
function person() {
alert(this.name) ;
}
o.test = person;//新建一個對象o,給它的方法test設置爲person這個函數
// o.test.apply();
//註釋下一行後,刪除上行註釋,結果彈出L
o.test();//undefined