[from] http://birdshome.cnblogs.com/archive/2005/06/07/169168.html
在"JavaScript中this關(guān)鍵字使用方法詳解"一文中,我曾例舉了在JavaScript和JScript中的8種this關(guān)鍵字的方式。這不又發(fā)現(xiàn)還有兩種this關(guān)鍵字的使用方式當(dāng)時(shí)沒有說到,現(xiàn)補(bǔ)充說明一下。并且通過第一種this關(guān)鍵字使用的說明,能讓我們更好的理解JavaScript作為Object-Based語言的本質(zhì)。
??? 一種是和JavaScript類中的定義有關(guān),我們知道當(dāng)我們定義如下類的時(shí)候:?










??? 方法ToString中的this.m_Properties就是100,那么下面這種定義呢?











??? 這時(shí)ToString中的這個(gè)this.m_Properties是啥?是-100。一定嗎?這個(gè)不一定了,這得看我們怎么調(diào)用這個(gè)ToString方法。



??? 這時(shí)的運(yùn)行結(jié)果居然是:-100和undefined。真是郁悶哈,怎么才能運(yùn)行fun得到-100呢?需要這樣來為fun賦值:
?


??? 呵呵,這樣就是-100了。好像挺廢話的,最終不還是調(diào)用的JSClass.ToString()嗎?這個(gè)我們后面再說,看看把這兩個(gè)JSClass合在一起是什么情況呢?
















??? 這兩個(gè)ToString()方法,和里面的this關(guān)鍵字它們是什么關(guān)系呢?看下面的示例:



??? 結(jié)果為:100和-100。這里的jsclass實(shí)際上是JavaScript的語言機(jī)制,通過new關(guān)鍵字的說明來創(chuàng)建的一個(gè)新的實(shí)例。而JSClass是什么呢?他們本就是對象實(shí)例,只是長得像個(gè)函數(shù),也像一個(gè)類的說明。對于this的問題,第一個(gè)jsclass.ToString()方法里的this是指新創(chuàng)建實(shí)例,而JSClass.ToString()方法里的this是值得JSClass這個(gè)對象實(shí)例。
??? 理解了這兩個(gè)this所指代的東西的不同本質(zhì),也就能更好的明白,為什么JavaScript叫做Object-Based的語言,而更加清楚它和Object-Oriented語言的本質(zhì)區(qū)別。
??? 回頭再說一下補(bǔ)充第二中this的使用方法,就是在使用eval方法的時(shí)候,這個(gè)時(shí)候的this是什么呢?看看:

??? 的結(jié)果是什么?是true!這是因?yàn)閑val內(nèi)代碼被執(zhí)行的作用域就是當(dāng)前頁面本身的說。
posted on 2005-06-07 13:37 birdshome 閱讀(1883) 評論(10) ?編輯?收藏收藏至365Key 所屬分類: JScript&DHTML開發(fā)
評論
# ?re: JScript中的"this"關(guān)鍵字使用方式補(bǔ)充??回復(fù)??
JSClass.m_Properties = -100;這種方式是定義靜態(tài)屬性,當(dāng)然不能用this來調(diào)用啦。
# ?re: JScript中的"this"關(guān)鍵字使用方式補(bǔ)充??回復(fù)??
有種類叫Function,任何函數(shù)/構(gòu)造器,都是它的實(shí)例改變這個(gè)構(gòu)造器的原型中的屬性自然和改變這個(gè)構(gòu)造器對象的屬性是不一樣的
# ?re: JScript中的"this"關(guān)鍵字使用方式補(bǔ)充??回復(fù)??
一點(diǎn)心得,請birdhome兄斧正!在javascript里面,自定義類的定義中的this和該類的方法定義中的this不一樣,得用call函數(shù)或者apply函數(shù)轉(zhuǎn)換。這對于用慣了c#剛剛接觸javascript面向?qū)ο缶幊痰呐笥眩ū救司褪瞧渲兄唬﹣碚f是個(gè)容易出錯(cuò)的地方。javascript函數(shù)定義中的this就是指函數(shù)本身,不能想當(dāng)然的認(rèn)為它指的是外層的類實(shí)例或者其他什么別的東西。prototype.js里面的bind方法可以用來轉(zhuǎn)換這個(gè)this。而且利用javascript函數(shù)的一個(gè)似乎是比較奇怪的特性——函數(shù)定義的參數(shù)個(gè)數(shù)可以跟函數(shù)調(diào)用時(shí)傳入的參數(shù)個(gè)數(shù)完全不同,可以很方便的實(shí)現(xiàn)轉(zhuǎn)換過程中的多參數(shù)傳遞問題,也就是說只要寫一個(gè)bind函數(shù),就可以轉(zhuǎn)換任意函數(shù)的上下文。
Function.prototype.Bind = function(obj){
var method = this;
return function(){
method.apply(obj,arguments);
}
}
在類定義中,把obj換成this,然后調(diào)用已定義方法的Bind方法,就可以轉(zhuǎn)換方法定義中的this指針了。上面函數(shù)中的arguments是調(diào)用時(shí)實(shí)際傳給function(){...}的參數(shù)數(shù)組,所以比如我要寫一個(gè)公開的Send(arg1,arg2,arg3),它里面有this指針,怎么辦呢?我先寫一個(gè)Pri_Send(arg1,arg2,arg3),然后在類定義(注意是類定義中)中這么寫:
this.Send = this.Pri_Send.Bind();
大功告成,現(xiàn)在可以盡情地在類的實(shí)例上使用Send方法了。而且對于那些參數(shù)個(gè)數(shù)不同或者根本沒有參數(shù)的方法,Bind()方法同樣適用,這都是arguments的功勞,呵呵。
此段代碼在IE6.0,FireFox1.0.7,opera 8.51下測試通過。應(yīng)該沒有太大的平臺問題。
# ?re: JScript中的"this"關(guān)鍵字使用方式補(bǔ)充??回復(fù)??
@hzy"自定義類的定義中的this和該類的方法定義中的this不一樣",這句話我沒有明白,你是說的這種情況嗎?














# ?re: JScript中的"this"關(guān)鍵字使用方式補(bǔ)充??回復(fù)??
真的非常慚愧,今天早上我用了簡單的幾行代碼就證明我上面的結(jié)論是錯(cuò)誤的。Bind()方法有用且正確,但在這里不需要,因?yàn)閖avascript并不像我昨天認(rèn)為的那樣奇怪,兩個(gè)this的確指的是同一個(gè)類型實(shí)例。
經(jīng)過仔細(xì)的審查(我自己的代碼),發(fā)現(xiàn)了這個(gè)錯(cuò)誤觀點(diǎn)的根源。
雖然在birdhome兄所說的情況下,兩個(gè)this指的是同一個(gè)東西,但在某些特定情況下,卻并非如此。其根本原因還請birdhome兄多多指教。謝。
我的代碼中就有兩處這樣的情況。
我使用正流行的ajax設(shè)計(jì)了一個(gè)簡單的AsyncCommunicator類,用來提供更豐富的編程接口。其中兩個(gè)功能就是“更細(xì)粒度的事件處理”和“超時(shí)處理”。
AsyncCommunicator類包含一個(gè)XmlHttpRequest屬性,這個(gè)屬性本身就是一個(gè)XMLHttpRequest類的實(shí)例。因此在AsyncCommunicator類的定義中,可以如下寫法訪問這個(gè)實(shí)例:
this.XmlHttpRequest
現(xiàn)在,我要給AsyncCommunicator類定義更多事件,方法是利用XMLHttpRequest的onreadystatechange屬性。如何做呢?
我是這么寫的:
AsyncCommunicator{
this.XmlHttpObj= GetNewXmlHttpRequest();
this.XmlHttpObj.onreadystatechange = this.EventStateChangeHandler;
this.EventStateChangeHandler = function(){
switch(this.XmlHttpObj.readyState){ case 3: this.OnTransferBack(this); break; case 4: if (!this.Pri_Aborted){
this.Pri_HasReceived = true; this.OnReceive(this);
switch(parseInt(((this.XmlHttpObj.status).toString()).charAt(0))){ case 1: this.OnReceive1xx(this); break;
case 2:
this.OnReceive2xx(this);
break;
case 3: this.OnReceive3xx(this);
break;
case 4:
this.OnReceive4xx(this);
break;
case 5: this.OnReceive5xx(this);
break;
default:
break;
} //switch } //(!this.Pri_Aborted) break; default: break;
} //switch
} //function
} //AsyncCommunitor
注意這句this.XmlHttpObj.onreadystatechange = this.EventStateChangeHandler,這句就是加Bind()方法正確,不加就會(huì)出錯(cuò)的源頭。經(jīng)過思考,我覺得這個(gè)this,更確切一點(diǎn)說,函數(shù)的上下文,已經(jīng)變了,不再是AsyncCommunitor,究竟是什么我也沒試出來,是否是XmlHttpObj?請birdhome兄指教。如果經(jīng)過Bind方法轉(zhuǎn)換,把this賦給Bind()方法作參數(shù),就可與更正這個(gè)問題。如下:
this.XmlHttpObj.onreadystatechange = this.EventStateChangeHandler.Bind(this);
我被這個(gè)問題折磨了一個(gè)晚上,因此一旦解決就緊接著犯了以偏概全的“左”傾錯(cuò)誤,呵呵,把所有內(nèi)部定義的方法都看成這種情況,因此每個(gè)方法都加了Bind()方法,想來真是慚愧,正如birdhome兄所言,通常情況下無須如此,因此已經(jīng)改正。
還有第二個(gè)情況,就是
this.AbortWhenTimeOut方法的調(diào)用。這個(gè)方法定義如下。:
this.Ori_AbortWhenTimeOut = function(){ if (!this.Pri_HasReceived) { this.Pri_Aborted = true; this.OnTimeOut(this); this.Abort(); } }
在xmlhttprequest對象的open方法之后和send方法之前加入window.setTimeout方法(放在send之后就不行,奇怪,請指教),參數(shù)中就包括這個(gè)this.AbortWhenTimeOut方法,現(xiàn)在想來,很可能是window.setTimeout方法改變了this.AbortWhenTimeOut方法的上下文,導(dǎo)致該方法定義中的this指針的含義發(fā)生變化,因此不能正常執(zhí)行。同樣,自從服用了Bind()之后,腰不酸了,背不痛了,腿也不抽筋了,走路也有勁了。呵呵。
關(guān)于上下文的這些奇妙變化(至少我覺得挺奇妙的,可能是受才智水平所限,慚愧),birdhome兄能否指教一二?
謝謝。
# ?re: JScript中的"this"關(guān)鍵字使用方式補(bǔ)充??回復(fù)??
PS,欽佩birdshome兄的專業(yè)水平。我隱約覺得javascript語言的諸多特性,是邏輯性很強(qiáng)的整體(其實(shí)事實(shí)也必然如此,用不著我去覺得,呵呵),例子舉的再多也只是“身在此山中”。遺憾我目前的水平還遠(yuǎn)遠(yuǎn)遠(yuǎn)遠(yuǎn)沒有達(dá)到可以跳出語言之外來論述語言的原理和本質(zhì)。不知道birdshome兄是否有這個(gè)空閑和興趣對javascript語言做一個(gè)總結(jié)性發(fā)言,不只是how 更重要的是why。這只是個(gè)非常即興的提議,更多的是某種期待。無論如何,我希望我自己也能做到,someday。
這差不多應(yīng)該也屬于技術(shù)區(qū)的非技術(shù),呵呵,類似的話不會(huì)說第二次了。
以后只討論技術(shù)。
# ?re: JScript中的"this"關(guān)鍵字使用方式補(bǔ)充??回復(fù)??
@hzy????this.XmlHttpObj.onreadystatechange = this.EventStateChangeHandler后,EventStateChangeHandler方法里的this在事件觸發(fā)后是指的window對象。第二個(gè)使用window.setTimeout也是同樣的問題,使用setTimeout觸發(fā)的方法,其內(nèi)部的this也是指的window。
????至于:對javascript語言做一個(gè)總結(jié)性發(fā)言。我不是很明白你具體指的內(nèi)容,畢竟JavaScript這門大家認(rèn)為"簡單"的小腳本,還是有挺多可圈點(diǎn)的內(nèi)容,似乎很難簡單的就能"總結(jié)性"道來:(