多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > web前端 > htmlcss > JavaScript學(xué)習(xí)--Item21 漂移的this

JavaScript學(xué)習(xí)--Item21 漂移的this

來源:程序員人生   發(fā)布時(shí)間:2016-06-29 16:56:44 閱讀次數(shù):4110次


而在 JavaScript 中,this 是動(dòng)態(tài)綁定,或稱為運(yùn)行期綁定的,這就致使 JavaScript 中的 this 關(guān)鍵字有能力具有多重含義,帶來靈活性的同時(shí),也為初學(xué)者帶來很多困惑。本文僅就這1問題展開討論,閱罷本文,讀者若能正確回答 JavaScript 中的 What ’s this 問題,作為作者,我就會(huì)覺得花費(fèi)這么多工夫,撰寫這樣1篇文章是值得的。

我們要記住1句話:this永久指向函數(shù)運(yùn)行時(shí)所在的對(duì)象!而不是函數(shù)被創(chuàng)建時(shí)所在的對(duì)象。也即:誰(shuí)調(diào)用,指向誰(shuí)。切記…

本文將分3種情況來分析this對(duì)象到底身處何方。

1、普通函數(shù)中的this

不管this身處何處,第1要?jiǎng)?wù)就是要找到函數(shù)運(yùn)行時(shí)的位置。

var name="全局"; function getName(){ var name="局部"; return this.name; }; alert(getName());

當(dāng)this出現(xiàn)在全局環(huán)境的函數(shù)getName中時(shí),此時(shí)函數(shù)getName運(yùn)行時(shí)的位置在

alert(getName());

明顯,函數(shù)getName所在的對(duì)象是全局對(duì)象,即window,因此this的安身的地方定然在window。此時(shí)的this指向window對(duì)象,則getName返回的this.name實(shí)際上是window.name,因此alert出來的是“全局”!

那末,當(dāng)this不是出現(xiàn)在全局環(huán)境的函數(shù)中,而是出現(xiàn)在局部環(huán)境的函數(shù)中時(shí),又會(huì)身陷何方呢?

var name="全局"; var xpg={ name:"局部", getName:function(){ return this.name; } }; alert(xpg.getName());

其中this身處的函數(shù)getName不是在全局環(huán)境中,而是處在xpg環(huán)境中。不管this身處何處,1定要找到函數(shù)運(yùn)行時(shí)的位置。此時(shí)函數(shù)getName運(yùn)行時(shí)的位置

alert(xpg.getName());

明顯,函數(shù)getName所在的對(duì)象是xpg,因此this的安身的地方定然在xpg,即指向xpg對(duì)象,則getName返回的this.name實(shí)際上是xpg.name,因此alert出來的是“局部”!

舉個(gè)例子鞏固1下:

var someone = { name: "Bob", showName: function(){ alert(this.name); } }; var other = { name: "Tom", showName: someone.showName } other.showName();  //Tom

this關(guān)鍵字雖然是在someone.showName中聲明的,但運(yùn)行的時(shí)候是other.showName,所以this指向other.showName函數(shù)確當(dāng)前對(duì)象,即other,故最后alert出來的是other.name。

2、閉包中的this

閉包也是個(gè)不安份子,本文暫且不對(duì)其過于贅述,簡(jiǎn)而言之:所謂閉包就是在1個(gè)函數(shù)內(nèi)部創(chuàng)建另外一個(gè)函數(shù),且內(nèi)部函數(shù)訪問了外部的變量。
浪子this與痞子閉包混在1起,可見將永毋寧日啊!

var name="全局"; var xpg={ name:"局部", getName:function(){ return function(){ return this.name; }; } }; alert(xpg.getName()());

此時(shí)的this明顯身處窘境,居然處在getName函數(shù)中的匿名函數(shù)里面,而該匿名函數(shù)又調(diào)用了變量name,因此構(gòu)成了閉包,即this身處閉包中。
不管this身處何處,1定要找到函數(shù)運(yùn)行時(shí)的位置。此時(shí)不能根據(jù)函數(shù)getName運(yùn)行時(shí)的位置來判斷,而是根據(jù)匿名函數(shù)的運(yùn)行時(shí)位置來判斷。

function (){ return this.name; };

明顯,匿名函數(shù)所在的對(duì)象是window,因此this的安身的地方定然在window,則匿名函數(shù)返回的this.name實(shí)際上是window.name,因此alert出來的就是“全局”!

那末,如何在閉包中使得this身處在xpg中呢?—緩存this

var name="全局"; var xpg={ name:"局部", getName:function(){ var that=this; return function(){ return that.name; }; } }; alert(xpg.getName()());

在getName函數(shù)中定義that=this,此時(shí)getName函數(shù)運(yùn)行時(shí)位置在

alert(xpg.getName());

則this指向xpg對(duì)象,因此that也指向xpg對(duì)象。在閉包的匿名函數(shù)中返回that.name,則此時(shí)返回的that.name實(shí)際上是xpg.name,因此就能夠alert出來 “局部”!

3、new關(guān)鍵字創(chuàng)建新對(duì)象

new關(guān)鍵字后的構(gòu)造函數(shù)中的this指向用該構(gòu)造函數(shù)構(gòu)造出來的新對(duì)象:

function Person(__name){ this.name = __name; //這個(gè)this指向用該構(gòu)造函數(shù)構(gòu)造的新對(duì)象,這個(gè)例子是Bob對(duì)象 } Person.prototype.show = function(){ alert(this.name); //this 指向Person,this.name = Person.name; } var Bob = new Person("Bob"); Bob.show(); //Bob

4、call與apply中的this

在JavaScript中能管的住this的估計(jì)也就非call與apply莫屬了。
call與apply就像this的父母1般,讓this住哪它就得住哪,不能不聽話!當(dāng)無(wú)參數(shù)時(shí),當(dāng)前對(duì)象為window

var name="全局"; var xpg={ name:"局部" }; function getName(){ alert(this.name); } getName(xpg); getName.call(xpg); getName.call();

其中this身處函數(shù)getName中。不管this身處何處,1定要找到函數(shù)運(yùn)行時(shí)的位置。此時(shí)函數(shù)getName運(yùn)行時(shí)的位置

getName(xpg);

明顯,函數(shù)getName所在的對(duì)象是window,因此this的安身的地方定然在window,即指向window對(duì)象,則getName返回的this.name實(shí)際上是window.name,因此alert出來的是“全局”!

那末,該call與apply登場(chǎng)了,由于this必須聽他們的指揮!

getName.call(xpg);

其中,call指定this的安身的地方就是在xpg對(duì)象,由于this被迫只能在xpg那安家,則此時(shí)this指向xpg對(duì)象, this.name實(shí)際上是xpg.name,因此alert出來的是“局部”!

5、eval中的this

對(duì)eval函數(shù),其履行時(shí)候仿佛沒有指定當(dāng)前對(duì)象,但實(shí)際上其this并不是指向window,由于該函數(shù)履行時(shí)的作用域是當(dāng)前作用域,即同等于在該即將里面的代碼填進(jìn)去。下面的例子說明了這個(gè)問題:

var name = "window"; var Bob = { name: "Bob", showName: function(){ eval("alert(this.name)"); } }; Bob.showName(); //Bob

6、沒有明確確當(dāng)前對(duì)象時(shí)的this

當(dāng)沒有明確的履行時(shí)確當(dāng)前對(duì)象時(shí),this指向全局對(duì)象window。
例如對(duì)全局變量援用的函數(shù)上我們有:

var name = "Tom"; var Bob = { name: "Bob", show: function(){ alert(this.name); } } var show = Bob.show; show();  //Tom

你可能也能理解成show是window對(duì)象下的方法,所以履行時(shí)確當(dāng)前對(duì)象時(shí)window。但局部變量援用的函數(shù)上,卻沒法這么解釋:

var name = "window"; var Bob = { name: "Bob", showName: function(){ alert(this.name); } }; var Tom = { name: "Tom", showName: function(){ var fun = Bob.showName; fun(); } }; Tom.showName();  //window

在閱讀器中setTimeout、setInterval和匿名函數(shù)履行時(shí)確當(dāng)前對(duì)象是全局對(duì)象window,這條我們可以看成是上1條的1個(gè)特殊情況。

var name = "Bob"; var nameObj ={ name : "Tom", showName : function(){ alert(this.name); }, waitShowName : function(){ setTimeout(this.showName, 1000); } }; nameObj.waitShowName();

所以在運(yùn)行this.showName的時(shí)候,this指向了window,所以最后顯示了window.name。

7、dom事件中的this

(1)你可以直接在dom元素中使用

<input id="btnTest" type="button" value="提交" onclick="alert(this.value))" />

分析:對(duì)dom元素的1個(gè)onclick(或其他如onblur等)屬性,它為所屬的html元素所具有,直接在它觸發(fā)的函數(shù)里寫this,this應(yīng)當(dāng)指向該html元素。

(2)給dom元素注冊(cè)js函數(shù)
a、不正確的方式

<script type="text/javascript"> function thisTest(){ alert(this.value); // 彈出undefined, this在這里指向?? } </script> <input id="btnTest" type="button" value="提交" onclick="thisTest()" />

分析:onclick事件直接調(diào)用thisTest函數(shù),程序就會(huì)彈出undefined。由于thisTest函數(shù)是在window對(duì)象中定義的,
所以thisTest的具有者(作用域)是window,thisTest的this也是window。而window是沒有value屬性的,所以就報(bào)錯(cuò)了。
b、正確的方式

<input id="btnTest" type="button" value="提交" /> <script type="text/javascript"> function thisTest(){ alert(this.value); } document.getElementById("btnTest").onclick=thisTest; //給button的onclick事件注冊(cè)1個(gè)函數(shù) </script>

分析:在前面的示例中,thisTest函數(shù)定義在全局作用域(這里就是window對(duì)象),所以this指代的是當(dāng)前的window對(duì)象。而通過document.getElementById(“btnTest”).onclick=thisTest;這樣的情勢(shì),實(shí)際上是將btnTest的onclick屬性設(shè)置為thisTest函數(shù)的1個(gè)副本,在btnTest的onclick屬性的函數(shù)作用域內(nèi),this歸btnTest所有,this也就指向了btnTest。其實(shí)如果有多個(gè)dom元素要注冊(cè)該事件,我們可以利用不同的dom元素id,用下面的方式實(shí)現(xiàn):

document.getElementById("domID").onclick=thisTest; //給button的onclick事件注冊(cè)1個(gè)函數(shù)。

由于多個(gè)不同的HTML元素雖然創(chuàng)建了不同的函數(shù)副本,但每一個(gè)副本的具有者都是相對(duì)應(yīng)的HTML元素,各自的this也都指向它們的具有者,不會(huì)造成混亂。
為了驗(yàn)證上陳述法,我們改進(jìn)1下代碼,讓button直接彈出它們對(duì)應(yīng)的觸發(fā)函數(shù):

<input id="btnTest1" type="button" value="提交1" onclick="thisTest()" /> <input id="btnTest2" type="button" value="提交2" /> <script type="text/javascript"> function thisTest(){ this.value="提交中"; } var btn=document.getElementById("btnTest1"); alert(btn.onclick); //第1個(gè)按鈕函數(shù) var btnOther=document.getElementById("btnTest2"); btnOther.onclick=thisTest; alert(btnOther.onclick); //第2個(gè)按鈕函數(shù) </script>

其彈出的結(jié)果是:

//第1個(gè)按鈕 function onclick(){ thisTest() } //第2個(gè)按鈕 function thisTest(){ this.value="提交中"; }

從上面的結(jié)果你1定理解的更透徹了。
By the way,每新建1個(gè)函數(shù)的副本,程序就會(huì)為這個(gè)函數(shù)副本分配1定的內(nèi)存。而實(shí)際利用中,大多數(shù)函數(shù)其實(shí)不1定會(huì)被調(diào)用,因而這部份內(nèi)存就被白白浪費(fèi)了。所以我們通常都這么寫:

<input id="btnTest1" type="button" value="提交1" onclick="thisTest(this)" /> <input id="btnTest2" type="button" value="提交2" onclick="thisTest(this)" /> <input id="btnTest3" type="button" value="提交3" onclick="thisTest(this)" /> <input id="btnTest4" type="button" value="提交4" onclick="thisTest(this)" /> <script type="text/javascript"> function thisTest(obj){ alert(obj.value); } </script>

這是由于我們使用了函數(shù)援用的方式,程序就只會(huì)給函數(shù)的本體分配內(nèi)存,而援用只分配指針。這樣寫1個(gè)函數(shù),調(diào)用的地方給它分配1個(gè)(指針)援用,這樣效力就高很多。固然,如果你覺得這樣注冊(cè)事件不能兼容多種閱讀器,可以寫下面的注冊(cè)事件的通用腳本:

//js事件 添加 EventUtil.addEvent(dom元素,事件名稱,事件觸發(fā)的函數(shù)名) 移除EventUtil.removeEvent(dom元素,事件名稱,事件觸發(fā)的函數(shù)名) var EventUtil = new eventManager(); //js事件通用管理器 dom元素 添加或移除事件 function eventManager() { //添加事件 //oDomElement:dom元素,如按鈕,文本,document等; ****** oEventType:事件名稱(如:click,如果是ie閱讀器,自動(dòng)將click轉(zhuǎn)換為onclick);****** oFunc:事件觸發(fā)的函數(shù)名 this.addEvent = function(oDomElement, oEventType, oFunc) { //ie if (oDomElement.attachEvent) { oDomElement.attachEvent("on" + oEventType, oFunc); } //ff,opera,safari等 else if (oDomElement.addEventListener) { oDomElement.addEventListener(oEventType, oFunc, false); } //其他 else { oDomElement["on" + oEventType] = oFunc; } } this.removeEvent = function(oDomElement, oEventType, oFunc) { //ie if (oDomElement.detachEvent) { oDomElement.detachEvent("on" + oEventType, oFunc); } //ff,opera,safari等 else if (oDomElement.removeEventListener) { oDomElement.removeEventListener(oEventType, oFunc, false); } //其他 else { oDomElement["on" + oEventType] = null; } } }

正像注釋寫的那樣,要注冊(cè)dom元素事件,用EventUtil.addEvent(dom元素,事件名稱,事件觸發(fā)的函數(shù)名)便可, 移除時(shí)可以這樣寫:EventUtil.removeEvent(dom元素,事件名稱,事件觸發(fā)的函數(shù)名)。這是題外話,不說了。


生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 亚洲jizzjizz| 天天天天鲁天天拍一拍 | 欧美性猛交xxxxx按摩欧美 | 欧美一区二区在线视频 | 67194在线午夜亚洲 | 三级在线视频 | 一区二区手机视频 | 2022偷拍午夜视频在线播放 | 日韩欧美亚洲 | 日本高清免费毛片久久看 | 免费毛片网站 | 在线欧美一区 | 在线观看麻豆精品国产不卡 | 最近中字视频在线观看 | 欧美激情一区二区三区视频高清 | 亚洲爱爱网 | 看黄网站大全 | 国产女人18毛片水真多18精品 | 美女免费视频是免费网站 | 亚洲乱码中文字幕 | 欧美另类亚洲 | 婷婷在线免费视频 | 在线观看www成人影院 | 国产美女亚洲精品久久久毛片 | 午夜dj视频在线高清免费 | 波多野吉衣在线多野结衣 | 波多野结中文字幕在线69视频 | 自拍偷拍视频网 | 视频精品一区 | a免费国产一级特黄aa大 | 久久久日韩精品国产成人 | 国产精品高清一区二区三区不卡 | 欧洲一区二区 | 91探花国产综合在线精品 | 日本一区二区三区欧美在线观看 | xxxxx国产| 尤物免费在线视频 | 福利在线免费 | 欧美性猛交xxxx黑人猛交 | 欧美毛片免费观看 | 免费一区二区三区四区 |