Javascript:對(duì)this瓶珊、new的認(rèn)識(shí)

javascript里的this指針邏輯上的概念也是實(shí)例化對(duì)象,這一點(diǎn)和java語(yǔ)言里的this指針是一致的耳舅,但是javascript里的this指針卻比java里的this難以理解的多染坯,究其根本原因總結(jié)起來(lái)有三個(gè)原因:

** 原因一:javascript是一個(gè)函數(shù)編程語(yǔ)言均芽,怪就怪在它也有this指針,說(shuō)明這個(gè)函數(shù)編程語(yǔ)言也是面向?qū)ο蟮恼Z(yǔ)言单鹿,說(shuō)的具體點(diǎn)掀宋,javascript里的函數(shù)是一個(gè)高階函數(shù),編程語(yǔ)言里的高階函數(shù)是可以作為對(duì)象傳遞的,同時(shí)javascript里的函數(shù)還有可以作為構(gòu)造函數(shù)劲妙,這個(gè)構(gòu)造函數(shù)可以創(chuàng)建實(shí)例化對(duì)象湃鹊,結(jié)果導(dǎo)致方法執(zhí)行時(shí)候this指針的指向會(huì)不斷發(fā)生變化,很難控制是趴。**
** 原因二:javascript里的全局作用域?qū)his指針有很大的影響涛舍,但是javascript里的this在沒(méi)有進(jìn)行new操作也會(huì)生效澄惊,這時(shí)候this往往會(huì)指向全局對(duì)象window唆途。
** 原因三:javascript里call和apply操作符可以隨意改變this指向,這看起來(lái)很靈活掸驱,但是這種不合常理的做法破壞了我們理解this指針的本意肛搬,同時(shí)也讓寫(xiě)代碼時(shí)候很難理解this的真正指向

讓我們先看一段代碼:

this.a = aaa;
console.log(a);  //aaa
console.log(this.a); //aaa
console.log(window.a); //aaa
console.log(this); //window
console.log(window); //window
console.log(this == window); //true
console.log(this === window); //true

在script標(biāo)簽里我們可以直接使用this指針,this指針就是window對(duì)象毕贼,我們看到即使使用三等號(hào)它們也是相等的温赔。全局作用域常常會(huì)干擾我們,使的我們不能很好的理解javascript語(yǔ)言的特性,這種干擾的本質(zhì)就是:
** 在javascript語(yǔ)言里全局作用域可以理解為window對(duì)象鬼癣,記住是window是對(duì)象而不是類陶贼,也就是說(shuō)window是被實(shí)例化的對(duì)象,這個(gè)實(shí)例化的過(guò)程是在頁(yè)面加載時(shí)候由javascript引擎完成的待秃,整個(gè)頁(yè)面里的要素都被濃縮到這個(gè)window對(duì)象拜秧,因?yàn)槌绦騿T無(wú)法通過(guò)編程語(yǔ)言來(lái)控制和操作這個(gè)實(shí)例化過(guò)程,所以開(kāi)發(fā)時(shí)候我們就沒(méi)有構(gòu)建這個(gè)this指針的感覺(jué)章郁,常常會(huì)忽視它枉氮,這就是干擾我們?cè)诖a里理解this指針指向window的情形。**
干擾的本質(zhì)還和function的使用有關(guān)暖庄,我們看看下面的代碼:

function ftn01(){ 
  console.log("I am ftn01!"); 
} 
var ftn02 = function(){ 
  console.log("I am ftn02!"); 
}

上面是我們經(jīng)常使用的兩種定義函數(shù)的方式聊替,第一種定義函數(shù)的方式在javascript語(yǔ)言稱作聲明函數(shù),第二種定義函數(shù)的方式叫做函數(shù)表達(dá)式培廓,這兩種方式我們通常認(rèn)為是等價(jià)的惹悄,但是它們其實(shí)是有區(qū)別的,而這個(gè)區(qū)別常常會(huì)讓我們混淆this指針的使用肩钠,我們?cè)倏纯聪旅娴拇a:

console.log(ftn01);//ftn01() 注意:在firebug下這個(gè)打印結(jié)果是可以點(diǎn)擊泣港,點(diǎn)擊后會(huì)顯示函數(shù)的定義 
console.log(ftn02);// undefined 
function ftn01(){
  console.log("I am ftn01!"); 
} 
var ftn02 = function(){
  console.log("I am ftn02!");
}

這又是一段沒(méi)有按順序執(zhí)行的代碼,先看看ftn02蔬将,打印結(jié)果是undefined爷速,undefined我在前文里講到了,在內(nèi)存的棧區(qū)已經(jīng)有了變量的名稱霞怀,但是沒(méi)有棧區(qū)的變量值惫东,同時(shí)堆區(qū)是沒(méi)有具體的對(duì)象,這是javascript引擎在預(yù)處理(群里東方說(shuō)預(yù)處理比預(yù)加載更準(zhǔn)確,我同意他的說(shuō)法廉沮,以后文章里我都寫(xiě)為預(yù)處理)掃描變量定義所致颓遏,但是ftn01的打印結(jié)果很令人意外,既然打印出完成的函數(shù)定義了滞时,而且代碼并沒(méi)有按順序執(zhí)行叁幢,這只能說(shuō)明一個(gè)問(wèn)題:

** 在javascript語(yǔ)言通過(guò)聲明函數(shù)方式定義函數(shù),javascript引擎在預(yù)處理過(guò)程里就把函數(shù)定義和賦值操作都完成了坪稽,在這里我補(bǔ)充下javascript里預(yù)處理的特性曼玩,其實(shí)預(yù)處理是和執(zhí)行環(huán)境相關(guān),在上篇文章里我講到執(zhí)行環(huán)境有兩大類:全局執(zhí)行環(huán)境和局部執(zhí)行環(huán)境窒百,執(zhí)行環(huán)境是通過(guò)上下文變量體現(xiàn)的黍判,其實(shí)這個(gè)過(guò)程都是在函數(shù)執(zhí)行前完成,預(yù)處理就是構(gòu)造執(zhí)行環(huán)境的另一個(gè)說(shuō)法篙梢,總而言之預(yù)處理和構(gòu)造執(zhí)行環(huán)境的主要目的就是明確變量定義顷帖,分清變量的邊界,但是在全局作用域構(gòu)造或者說(shuō)全局變量預(yù)處理時(shí)候?qū)τ诼暶骱瘮?shù)有些不同渤滞,聲明函數(shù)會(huì)將變量定義和賦值操作同時(shí)完成贬墩,因此我們看到上面代碼的運(yùn)行結(jié)果。由于聲明函數(shù)都會(huì)在全局作用域構(gòu)造時(shí)候完成妄呕,因此聲明函數(shù)都是window****對(duì)象的屬性陶舞,這就說(shuō)明為什么我們不管在哪里聲明函數(shù),聲明函數(shù)最終都是屬于window對(duì)象的原因了趴腋。
關(guān)于函數(shù)表達(dá)式的寫(xiě)法還有秘密可以探尋吊说,我們看下面的代碼:

function ftn03(){
  var ftn04 = function(){
    console.log(this);// window 
  };
  ftn04(); 
} 
ftn03();

運(yùn)行運(yùn)行結(jié)果我們發(fā)現(xiàn)ftn04雖然在ftn03作用域下,但是執(zhí)行它里面的this指針也是指向window优炬,其實(shí)函數(shù)表達(dá)式的寫(xiě)法我們大多數(shù)更喜歡在函數(shù)內(nèi)部寫(xiě)颁井,因?yàn)槁暶骱瘮?shù)里的this指向window這已經(jīng)不是秘密,但是函數(shù)表達(dá)式的this指針指向window卻是常常被我們所忽視蠢护,特別是當(dāng)它被寫(xiě)在另一個(gè)函數(shù)內(nèi)部時(shí)候更加如此雅宾。

其實(shí)在javascript語(yǔ)言里任何匿名函數(shù)都是屬于window對(duì)象,它們也都是在全局作用域構(gòu)造時(shí)候完成定義和賦值葵硕,但是匿名函數(shù)是沒(méi)有名字的函數(shù)變量眉抬,但是在定義匿名函數(shù)時(shí)候它會(huì)返回自己的內(nèi)存地址,如果此時(shí)有個(gè)變量接收了這個(gè)內(nèi)存地址懈凹,那么匿名函數(shù)就能在程序里被使用了蜀变,因?yàn)槟涿瘮?shù)也是在全局執(zhí)行環(huán)境構(gòu)造時(shí)候定義和賦值,所以匿名函數(shù)的this指向也是window對(duì)象介评,所以上面代碼執(zhí)行時(shí)候ftn04的this也是指向window库北,因?yàn)閖avascript變量名稱不管在那個(gè)作用域有效爬舰,堆區(qū)的存儲(chǔ)的函數(shù)都是在全局執(zhí)行環(huán)境時(shí)候就被固定下來(lái)了鏈,變量的名字只是一個(gè)指代而已寒瓦。

這下子壞了情屹,this都指向window,那我們到底怎么才能改變它了杂腰?

先說(shuō)一個(gè)結(jié)論:this都是指向?qū)嵗瘜?duì)象垃你,之前講那么多情況this都指向window,就是因?yàn)檫@些時(shí)候只做了一次實(shí)例化操作喂很,而這個(gè)實(shí)例化都是在實(shí)例化window對(duì)象惜颇,所以this都是指向window。我們要把this從window變成別的對(duì)象恤筛,就得要讓function被實(shí)例化官还,那如何讓javascript的function實(shí)例化呢芹橡?答案就是使用new操作符毒坛。我們看看下面的代碼:

<script type="text/javascript"> 
//方式一
var obj = { 
  name:"sharpxiajun", 
  job:"Software", 
  show:function(){
    console.log("Name:" + this.name + ";Job:" + this.job);  
    console.log(this);
  // Object{ name="sharpxiajun", job="Software", show=function()} } 
}; 
//方式二
 var otherObj = new Object(); 
 otherObj.name = "xtq"; 
 otherObj.job = "good"; 
 otherObj.show = function(){ 
   console.log("Name:" + this.name + ";Job:" + this.job);   
   console.log(this);
   // Object { name="xtq", job="good", show=function()} }; 
   obj.show();//Name:sharpxiajun;Job:Software  
   otherObj.show();//Name:xtq;Job:good
</script>

** 這是我上篇講到的關(guān)于this使用的一個(gè)例子,寫(xiě)法一是我們大伙都愛(ài)寫(xiě)的一種寫(xiě)法林说,里面的this指針不是指向window的煎殷,而是指向Object的實(shí)例,其實(shí)Object就是面向?qū)ο蟮念愅嚷幔罄ㄌ?hào)里就是實(shí)例對(duì)象了豪直,即obj和otherObj。Javascript里通過(guò)字面量方式定義對(duì)象的方式是new Object的簡(jiǎn)寫(xiě)珠移,二者是等價(jià)的弓乙,目的是為了減少代碼的書(shū)寫(xiě)量,可見(jiàn)即使不用new操作字面量定義法本質(zhì)也是new操作符钧惧,所以通過(guò)new改變this指針的確是不過(guò)攻破的真理暇韧。**

下面我貼出在《javascript高級(jí)編程》里對(duì)new操作符的解釋:
new操作符會(huì)讓構(gòu)造函數(shù)產(chǎn)生如下變化:
1.創(chuàng)建一個(gè)新對(duì)象;
2.將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此this就指向了這個(gè)新對(duì)象)浓瞪;
3.執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性)懈玻;
4.返回新對(duì)象

關(guān)于第二點(diǎn)其實(shí)很容易讓人迷惑,例如前面例子里的obj和otherObj乾颁,obj.show()涂乌,里面this指向obj,我以前文章講到一個(gè)簡(jiǎn)單識(shí)別this方式就是看方法調(diào)用前的對(duì)象是哪個(gè)this就指向哪個(gè)英岭,其實(shí)這個(gè)過(guò)程還可以這么理解湾盒,在全局執(zhí)行環(huán)境里window就是上下文對(duì)象,那么在obj里局部作用域通過(guò)obj來(lái)代表了诅妹,這個(gè)和window的理解是一致的罚勾。

第四點(diǎn)也要著重講下,記住構(gòu)造函數(shù)被new操作,要讓new正常作用最好不能在構(gòu)造函數(shù)里寫(xiě)return荧库,沒(méi)有return的構(gòu)造函數(shù)都是按上面四點(diǎn)執(zhí)行堰塌,有了return情況就復(fù)雜了,這個(gè)知識(shí)我會(huì)在講prototype時(shí)候講到分衫。

Javascript還有一種方式可以改變this指針场刑,這就是call方法和apply方法,call和apply方法的作用相同蚪战,就是參數(shù)不同牵现,call和apply的第一個(gè)參數(shù)都是一樣的,但是后面參數(shù)不同邀桑,apply第二個(gè)參數(shù)是個(gè)數(shù)組瞎疼,call從第二個(gè)參數(shù)開(kāi)始后面有許多參數(shù)。Call和apply的作用是什么壁畸,這個(gè)很重要贼急,重點(diǎn)描述如下:

** Call和apply是改變函數(shù)的作用域(有些書(shū)里叫做改變函數(shù)的上下文)**
** Call和apply是將this指針指向方法的第一個(gè)參數(shù)。**

var name = "sharpxiajun";
function ftn(name){ 
  console.log(name); 
  console.log(this.name);
  console.log(this); 
} 
ftn("101");
// 101
// sharpxiajun
//window
var obj = { name:"xtq" }; 
ftn.call(obj,"102");
//102
//xtq
//obj

我們看到apply和call改變的是this的指向捏萍,這點(diǎn)在開(kāi)發(fā)里很重要太抓,開(kāi)發(fā)里我們常常被this所迷惑,迷惑的根本原因我在上文講到了令杈,這里我講講表面的原因:

表面原因就是我們定義對(duì)象使用對(duì)象的字面表示法走敌,字面表示法在簡(jiǎn)單的表示里我們很容易知道this指向?qū)ο蟊旧恚沁@個(gè)對(duì)象會(huì)有方法逗噩,方法的參數(shù)可能會(huì)是函數(shù)掉丽,而這個(gè)函數(shù)的定義里也可能會(huì)使用this指針,如果傳入的函數(shù)沒(méi)有被實(shí)例化過(guò)和被實(shí)例化過(guò)异雁,this的指向是不同捶障,有時(shí)我們還想在傳入函數(shù)里通過(guò)this指向外部函數(shù)或者指向被定義對(duì)象本身,這些亂七八糟的情況使用交織在一起導(dǎo)致this變得很復(fù)雜片迅,結(jié)果就變得糊里糊涂残邀。
其實(shí)理清上面情況也是有跡可循的,就以定義對(duì)象里的方法里傳入函數(shù)為例:
** 情形一:傳入的參數(shù)是函數(shù)的別名柑蛇,那么函數(shù)的this就是指向window芥挣;**
** 情形二:傳入的參數(shù)是被new過(guò)的構(gòu)造函數(shù),那么this就是指向?qū)嵗膶?duì)象本身耻台;**
** 情形三:如果我們想把被傳入的函數(shù)對(duì)象里this的指針指向外部字面量定義的對(duì)象空免,那么我們就是用apply和call**

    function fn() {
        alert(this);
    }

    var people = {
        name: "shuai",
        job: "IT",
        show: function(fn) {
            fn();
        }
    }
    people.show(fn);
    function fn() {
        this.name = '我是fn';
    }
    fn.prototype.say = function() {
        alert(this.name);
    }
    var obj = new fn();

    var people = {
        name: "shuai",
        job: "IT",
        show: function(obj) {
            obj.say();
        }
    }
    people.show(obj);
    function fn() {
        this.name = '我是fn';
    }
    fn.prototype.say = function() {
        alert(this.name);
    }
    var obj = new fn();
    
    var people = {
        name: "shuai",
        job: "IT",
        show: function(obj) {
            obj.say.call(people);
        }
    }
    people.show(obj);

參考文獻(xiàn):http://www.cnblogs.com/sharpxiajun/p/4148932.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市盆耽,隨后出現(xiàn)的幾起案子蹋砚,更是在濱河造成了極大的恐慌扼菠,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坝咐,死亡現(xiàn)場(chǎng)離奇詭異循榆,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)墨坚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門秧饮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人泽篮,你說(shuō)我怎么就攤上這事盗尸。” “怎么了帽撑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵泼各,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我亏拉,道長(zhǎng)扣蜻,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任专筷,我火速辦了婚禮弱贼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘磷蛹。我一直安慰自己,他們只是感情好溪烤,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布味咳。 她就那樣靜靜地躺著,像睡著了一般檬嘀。 火紅的嫁衣襯著肌膚如雪槽驶。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,337評(píng)論 1 310
  • 那天鸳兽,我揣著相機(jī)與錄音掂铐,去河邊找鬼。 笑死揍异,一個(gè)胖子當(dāng)著我的面吹牛全陨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播衷掷,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辱姨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了戚嗅?” 一聲冷哼從身側(cè)響起雨涛,我...
    開(kāi)封第一講書(shū)人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤枢舶,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后替久,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體凉泄,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年蚯根,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了旧困。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稼锅,死狀恐怖吼具,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情矩距,我是刑警寧澤拗盒,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站锥债,受9級(jí)特大地震影響陡蝇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哮肚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一登夫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧允趟,春花似錦深碱、人聲如沸钥庇。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)景殷。三九已至校套,卻和暖如春集灌,著一層夾襖步出監(jiān)牢的瞬間推汽,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工弧蝇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碳褒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓看疗,卻偏偏與公主長(zhǎng)得像沙峻,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鹃觉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容