關於這個this關鍵字,也是很多項目中常常被用到的,那么,有人也許會問,干嘛要用this呢,在函數被調用時,直接指明是什么對象在調用不就行了?還整那么個模模糊糊的概念出來干嘛?不過嘛,存在即真理,既然有這么個東西,那也就有他存在的意義,下面來看看吧。
首先,我們要先回憶一下js函數都有哪幾種調用的場合,有如下幾種場合:
1、很常規的調用(即直接調用,其實你發現也是全局調用);
2、作為某個對象的豆哥方法被調用;
3、作為構造函數,用來新建某個新對象(object);
4、很讓人頭大的apply調用(在實現部分繼承的時候經常這么干)。
好了,一起來看看上述幾種情況下this關鍵字是怎樣被玩的出神入化的。
一、純粹的函數調用
這是函數的最通常用法,屬於全局性調用,因此this就代表全局對象Global,那么這里Global很多人又很迷惑了,實則在瀏覽器環境下,Global也即是window對象,global對象是單體內置對象,即不依賴宿主環境的對象,而window對象依賴瀏覽器。
看下面這段代碼:
function test(){
this.name = "dearxiangxiao";
console.log(this.name );
}
test(); //dearxiangxiao
感覺還是很神奇的,不知不覺test函數里面定義的屬性,在外面也可以讀取了?對代碼做一些修改,如下:
var name = "xiangxiao";
function test(){
this.name = "dearxiangxiao";
}
test();
alert(name); // dearxiangxiao
可以看出,在執行完test函數之后,name的值被改變了,原因何在?這里就是這個調用test的對象是Global在作怪,既然test是被全局對象Global調用的,那么this也就指向Global對象了,全局對象的屬性,當然可以讀取並修改了,沒啥錯。
二、作為對象方法的調用
函數還可以作為某個對象的方法調用,這時this就指這個上級對象,也來看一段代碼:
function test(){
console.log("my name is "+this.name + " and my profession is "+this.profession);
};
var person = {};
person .name= "dearxiangxiao";
person.profession = "projector";
person.interduce= test;
person .interduce(); // my name is dearxiangxiao,and my profession is projector
這里很好理解,既然是person在調用test函數,那么理所應當的this指向的是person實體,也就是前面說的調用函數的上一級對象,它的name和profession 屬性當然應該被讀取出來了。
三、作為構造函數調用
所謂構造函數,就是通過這個函數生成一個新對象(object)。這時,this就指這個新對象,也來看一段代碼,將一中的例子做輕微的修改:
var name = "xiangxiao";
function Person(){
this.name = "dearxiangxiao";
}
var person1 = new Person();
console.log(name); // xiangxiao
console.log(person1.name); // dearxiangxiao
可以看出,this指向的對象是剛剛新建的person1,讀取出了它的名稱dearxiangxiao,而直接打印name變量,值仍然未變,為之前的xiangxiao。這更加表明this指向person1,而不是Global對象。
四、apply調用
apply()是函數對象的一個方法,它的作用是改變函數的調用對象(實則是將某某對象的某個方法放到另一個好基友對象那里去執行),它的第一個參數就表示改變后的調用這個函數的對象。因此,this指的就是這第一個參數。
關於這個apply,可能大多數人不太喜歡用它,要想調用某個對象直接調用不就好了么?但是應該想到,假如你想調用別人寫好的某個方法,某些參數變量卻要用到你自己的,怎么辦?apply和call就派上用場了,這也是js面向對象思維轉換的重要一環,必須理解的(關於apply和call具體詳情,請看我的另一篇博文:js面向對象思維轉換的一個階梯:apply和call)。
下面還是來看個例子吧,這里把三中的例子做一些輕微的修改:
var name = "xiangxiao";
function test(){
console.log(this.name);
}
var person1 = new Person();
person1.name = "dearxiangxiao";
person1.interduce = test;
person1.interduce.apply(); // 這里輸出的四xiangxiao
怎么回事,不是說好了的要改變函數的調用對象么?怎么還是被Global調用了?不急不急,來看看apply后面的括號里,沒任何東西,默認沒有殘數時是全局對象Global,因此,此處也就真的是調用出了Global的name變量。那person1.interduce.apply()怎么理解呢?可以這么理解:將person1實體的interduce方法放到Global對象上去執行。
好了,我們剛剛在前面說了,apply后面括號里的第一個參數,即為this的指向,那么改一改上面的最后一句代碼吧,如下:
person1.interduce.apply(person1); // 這里輸出的就是dearxiangxiao
得到person1的name屬性值了,突然冒出個想法,這里person1.interduce.apply(person1) 理解出來貌似很拗口額:將person1實體對象的interduce方法放到person1實體對象上去執行,什么鬼?自己的方法自己直接調用不好么?寫成 person1.interduce()就行了噻!!!當然可以,那樣更簡潔,不過,這就是apply方法的特點所致吧,自己的方法,轉一圈回到自己手里被調用了,還給出個冠冕堂皇的解釋,哈哈,就不吐槽了,我們還是要看到apply帶給我們的諸多好處的。
這篇博文就是這么多內容了,希望大家會喜歡。