您好,登錄后才能下訂單哦!
這篇文章主要詳解Javascript中的this關(guān)鍵字,內(nèi)容清晰明了,對(duì)此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會(huì)有幫助。
一、基本的:
function doSomething(){ alert(this.id); } alert(window.doSomething);//證明了doSomething是屬于window的 doSomething();//undefined window.onload = function(){ document.getElementById("div2").onclick = doSomething;//div2 document.getElementById("div3").onclick = function(){doSomething();}//undefined }
1、對(duì)于doSomething這個(gè)函數(shù):
function doSomething(){ alert(this.id); }
這個(gè)函數(shù)是全局函數(shù),這種全局函數(shù)實(shí)際上是屬于window的(可以通過(guò)window.doSomething
來(lái)訪問(wèn)),如果直接調(diào)用,那么根據(jù)“this always refers to the “owner” of the function we're executing”,那么函數(shù)中的this就是window,但是window沒(méi)有id屬性,所以顯示“undefined”;
2、在html元素中這樣調(diào)用
<div id="div1" onclick="doSomething();">div1</div>
這時(shí)也會(huì)顯示“undefined”,這就相當(dāng)于如下代碼:
document.getElementById("div1").onclick = function(){doSomething();}
當(dāng)點(diǎn)擊div1時(shí),調(diào)用屬于window的doSomething函數(shù),所以也是顯示“undefined”;
3、通過(guò)js來(lái)綁定事件,在div2載入過(guò)后:
document.getElementById("div2").onclick = doSomething;
當(dāng)點(diǎn)擊div2時(shí),顯示“div2”,因?yàn)樵诮odiv2的onclick賦值,是將doSomething拷貝了一次,這時(shí)拷貝的這個(gè)函數(shù)是屬于div2的了,跟屬于window的doSomething沒(méi)有任何關(guān)系了。點(diǎn)擊div2時(shí),就會(huì)觸發(fā)屬于div2的doSomething,這里的this就是指div2。
二、attachEvent和addEventListener 
attachEvent是在ie中綁定事件的方法,會(huì)將相應(yīng)函數(shù)拷貝到全局(即響應(yīng)函數(shù)的owner為window),但是在DOM標(biāo)準(zhǔn)中,addEventListener綁定的事件時(shí)拷貝的響應(yīng)函數(shù)的owner為事件所綁定的對(duì)象
function doSomething(){ alert(this.id); alert(this == window); } window.onload = function(){ var div1 = document.getElementById("div1"); if(div1.attachEvent){ div1.attachEvent("onclick",doSomething); document.body.appendChild(document.createTextNode("attachEvent")); }else if(div1.addEventListener){ div1.addEventListener("click",doSomething,false); document.body.appendChild(document.createTextNode("addEventListener")); }else{ div.onclick = doSomething; } }
對(duì)于函數(shù)doSomething
function doSomething(){ alert(this.id); alert(this == window); }
1、使用attachEvent綁定到div1的click事件上,doSometing會(huì)被復(fù)制到window,這時(shí)doSomething里面的this指的是window,點(diǎn)擊div1時(shí)會(huì)顯示“undefined”和“true”
2、使用addEventListener綁定div1的click事件,這時(shí)將doSomething拷貝,這個(gè)拷貝過(guò)后的函數(shù)是屬于div1的,所以點(diǎn)擊div1時(shí)會(huì)顯示“div1”和“false”,看如下代碼
var obj = new Object(); obj.color = "black"; obj.showColor = function(){ alert(this.color); alert(this == window); } obj.showColor(); var div1 = document.getElementById("div1"); div1.attachEvent("onclick",obj.showColor);
此時(shí)點(diǎn)擊div1的時(shí)候,會(huì)顯示“undefined”和“true”,如果attachEvent僅僅是引用obj.showColor的話,那么this還是應(yīng)該指的是obj,但是實(shí)際上這里this指的是window,所以我認(rèn)為這里不是引用,而是拷貝到全局的。
三、關(guān)于對(duì)象冒充的繼承方式 
1、new與不new的區(qū)別
對(duì)于如下function
function ClassA(sColor){ this.color = sColor; this.sayColor = function(){ alert(this.color); } }
這是一個(gè)類還是一個(gè)函數(shù)?隨你而定!
如果你認(rèn)為這是一個(gè)函數(shù),那么我們可以這樣來(lái)調(diào)用它:
ClassA("red");
“red”是傳遞的一個(gè)參數(shù),ClassA中的this指的是當(dāng)然就是指的window了,所以現(xiàn)在window有了color屬性和sayColor方法,并且color有“red”這個(gè)值。
這是調(diào)用sayColor
或者window.sayColor
都可以顯示“red”;
window.sayColor();
如果你認(rèn)為這是一個(gè)類,那么我們應(yīng)該這樣使用它:
var obj = new ClassA("red");
new這個(gè)關(guān)鍵詞的出現(xiàn)讓上面這一句代碼增加了不少內(nèi)容:首先,創(chuàng)建一個(gè)Object實(shí)例,然后,將ClassA中的this指向創(chuàng)建的這個(gè)Object中,最后返回這個(gè)Object,所以返回的這個(gè)Object就賦值給了obj。所以我們可以說(shuō)this指向的是obj,obj擁有了color屬性和sayColor方法,并且color屬性值為“red”。
2、函數(shù)的owener
function showId(){ alert(this.id); } window.onload = function(){ var div1 = document.getElementById("div1"); div1.onclick = showId; div1.show = showId; div1.show(); var obj = new Object(); obj.id = "obj"; obj.show = showId; obj.show(); }
我們可以將showId這個(gè)函數(shù)賦值給click事件,也可以賦值給任何一個(gè)對(duì)象的任何一個(gè)屬性,這是也會(huì)拷貝showId這個(gè)方法的,所以我們?cè)谡{(diào)用div1.show方法時(shí),this是指向div1的,在調(diào)用obj.show時(shí),this指向的是obj的。
3、對(duì)象冒充的原理
下面的代碼是通過(guò)對(duì)象冒充方法實(shí)現(xiàn)的繼承
function ClassA(sColor){ this.color = sColor; this.sayColor = function(){ alert(this.color); } } function ClassB(sColor,sName){ this.newMethod = ClassA; this.newMethod(sColor); delete this.newMethod; this.name = sName; this.sayName = function(){ alert(this.name); } } var objB = new ClassB("color of objB","name of objB"); objB.sayColor();
objB是ClassB的一個(gè)實(shí)例,objB是如何擁有color屬性和sayColor方法的呢?
首先從實(shí)例化的代碼看起:
var objB = new ClassB("color of objB","name of objB");
這里ClassB是個(gè)類,ClassB中的this當(dāng)然就是指的objB這個(gè)對(duì)象;
在ClassB中,前三行代碼會(huì)用到ClassA,這時(shí)就把ClassA看作一個(gè)函數(shù),而不是類。
我們?nèi)绻苯诱{(diào)用ClassA這個(gè)函數(shù),那么很顯然,ClassA中的this指的就是window對(duì)象了,所以我們先將ClassA拷貝到objB的newMethod這個(gè)屬性中(this.newMethod = ClassA
),
然后再調(diào)用this.newMethod,這是這個(gè)方法的owener明顯的已經(jīng)成了this,而ClassB中的this在當(dāng)前指的是objB,所以此時(shí)ClassA中(嚴(yán)格的說(shuō)是newMethod中,因?yàn)檫@是拷貝過(guò)后的,跟ClassA已經(jīng)是兩個(gè)方法了)的this就是指的objB,這樣在通過(guò)newMethod的調(diào)用,就給objB賦值了color屬性和sayColor方法。用call和apply方法來(lái)實(shí)現(xiàn)繼承實(shí)際上也是一個(gè)原理,call和apply可以看作是改變方法的owner的方法,而這里ClassB中的前三句代碼也就是起這個(gè)作用的。
四、prototype1.6中的Class.create
prototype1.6中的Class.create方法大致如下:
var Class = { create: function() { // function klass() { this.initialize.apply(this, arguments); } // for (var i = 0; i < properties.length; i++) klass.addMethods(properties[i]); // return klass; } };
在使用的時(shí)候是這樣的:
var Person = Class.create({ initialize:function(name){ this.name = name; }, say:function(message){ alert(this.name + ":" + message); } }); var aPerson = new Person("name1"); aPerson.say("hello1");
Person實(shí)際上是通過(guò)Class.create這個(gè)方法所返回的klass(klass是Class.create中的局部變量,是一個(gè)function),Class.create所傳遞的參數(shù)(initialize方法和say方法)傳遞到create方法中的properties數(shù)組中并且通過(guò)addMethods方法讓klass的prototype擁有這些方法。那么最關(guān)鍵的地方也是最難以理解的地方是:klass中的this究竟是指的是什么。仔細(xì)想一想就不難得到答案,Person實(shí)際上就是klass,而我們?cè)趯?shí)例化Person對(duì)象的時(shí)候,是用了new關(guān)鍵詞的:
var aPerson = new Person("name1");
這就等價(jià)于
var aPerson = new klass("name1");
雖然klass在外面不能被訪問(wèn)到,但是這樣能很輕易的說(shuō)明問(wèn)題,klass是一個(gè)類而不是簡(jiǎn)單的一個(gè)函數(shù)(我們看作如此,因?yàn)橛昧薾ew關(guān)鍵字),那么klass中的this就指的是聲明的實(shí)例,在這里就是aPerson,aPerson通過(guò)klass的prototype能夠擁有initialize方法和say方法,在new的過(guò)程中,也會(huì)執(zhí)行klass中的代碼,所以initialize在實(shí)例化的時(shí)候會(huì)執(zhí)行,即構(gòu)造函數(shù)。(在klass里兩個(gè)this都是指的aPerson,為什么還要通過(guò)apply調(diào)用一次呢?這主要是為了傳遞構(gòu)造函數(shù)的參數(shù),用apply方法可以將數(shù)目不定的多個(gè)參數(shù)通過(guò)數(shù)組方便的傳到initialize方法中去。)
五、再分析幾個(gè)例子
從別的文章里看到的例子,我在這里分析一下:
1、運(yùn)行如下代碼
function OuterFoo(){ this.Name = 'Outer Name'; function InnerFoo(){ var Name = 'Inner Name'; alert(Name + ', ' + this.Name); } return InnerFoo; } OuterFoo()();
所顯示的結(jié)果是“Inner Name, Outer Name”
OuterFoo是一個(gè)函數(shù)(而不是類),那么第一句
this.Name = 'Outer Name';
中的this指的是window對(duì)象,所以O(shè)uterFoo()過(guò)后window.Name = ‘Outer Name';
并且將InnerFoo返回,此時(shí)InnerFoo同樣是一個(gè)函數(shù)(不是類),執(zhí)行InnerFoo的時(shí)候,this同樣指window,所以InnerFoo中的this.Name的值為”O(jiān)uter Name”(window.Name充當(dāng)了一個(gè)中轉(zhuǎn)站的角色,讓OuterFoo能夠向InnerFoo傳遞“Outer Name”這個(gè)值),而Name的值即為局部變量”Inner Name”
2、運(yùn)行如下代碼
function JSClass(){ this.m_Text = 'division element'; this.m_Element = document.createElement('DIV'); this.m_Element.innerHTML = this.m_Text; if(this.m_Element.attachEvent) this.m_Element.attachEvent('onclick', this.ToString); else if(this.m_Element.addEventListener) this.m_Element.addEventListener('click', this.ToString,false); else this.m_Element.onclick = this.ToString; } JSClass.prototype.Render = function(){ document.body.appendChild(this.m_Element); } JSClass.prototype.ToString = function(){ alert(this.m_Text); alert(this == window); } window.onload = function(){ var jc = new JSClass(); jc.Render(); jc.ToString(); }
點(diǎn)擊“division element”會(huì)顯示“undefined”,在ie下還要顯示“true”,其他瀏覽器中還要顯示“false”。
實(shí)例聲明和調(diào)用實(shí)例方法都沒(méi)什么可說(shuō)的,元素的click事件的綁定到了一個(gè)實(shí)例的方法,那么通過(guò)addEventListener綁定到的方法是拷貝過(guò)后的,所以this指的是html元素,這個(gè)元素沒(méi)有m_Text屬性(m_Text屬性是屬于JSClass的實(shí)例的,即屬于jc的),所以點(diǎn)擊元素顯示undefined,attachEvent綁定的事件會(huì)將函數(shù)復(fù)制到全局,此時(shí)this指的是window對(duì)象,點(diǎn)擊元素也會(huì)顯示“undefined”。只有在調(diào)用jc.ToString()方法是,this指的是jc這個(gè)對(duì)象,因?yàn)閖c擁有m_Text,所以能夠顯示“division element”。
六、總結(jié)
怎樣在一個(gè)代碼環(huán)境中快速的找到this所指的對(duì)象呢?我想要注意以下三個(gè)方面:
1、 要清楚的知道對(duì)于函數(shù)的每一步操作是拷貝還是引用(調(diào)用)
2、 要清楚的知道函數(shù)的擁有者(owner)是什么
3、 對(duì)于一個(gè)function,我們要搞清楚我們是把它當(dāng)作函數(shù)使用還是在當(dāng)作類使用
補(bǔ)充:
1.在實(shí)例和類上都可以直接定義函數(shù)
2.不能在實(shí)例上使用prototype定義函數(shù),只能在類上使用prototype定義函數(shù)
3.類上直接定義的函數(shù)不能使用this訪問(wèn)對(duì)象的屬性
4.在類的prototype上建立的函數(shù)可以用this,在類內(nèi)部定義的函數(shù)可以使用this,在對(duì)象實(shí)例上建立的函數(shù)額可以this
window.alert=function (msg) { document.write(msg+"<br>"); } function say() { this.f="props"; this.func3=function(){alert("f3,"+this.f);} } say.func1=function(){alert("func1,"+this.f);}; //Error,類上直接定義的函數(shù),不能使用this say.prototype.func2=function(){alert("func2,"+this.f);} say.func1(); (new say()).func2(); say.func2(); //Error, 在用prototype定義的函數(shù),必須實(shí)例化對(duì)象才能調(diào)用 say.func3(); //Error,在類上定義的函數(shù),必須實(shí)例化才能調(diào)用 (new say()).func3(); var obj={ fld1:10, func1:function(msg){alert(msg);}, func4:function(){alert(this.fld1);} } obj.prototype.func=function(){alert("func");}; //Error 實(shí)例對(duì)象上不能使用prototype定義對(duì)象 obj.func2=function(){alert("func2,"+this.fld1);}; //ok,實(shí)例上直接定義的函數(shù)可以使用this,訪問(wèn)對(duì)象的屬性 alert(obj.fld1); obj.func1("func1"); obj.func2(); obj.func4();
看完上述內(nèi)容,是不是對(duì)詳解Javascript中的this關(guān)鍵字有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。