摘要:首先,必須搞清楚在里面,函數(shù)的幾種調(diào)用方式普通函數(shù)調(diào)用作為方法來(lái)調(diào)用作為構(gòu)造函數(shù)來(lái)調(diào)用使用方法來(lái)調(diào)用方法箭頭函數(shù)但是不管函數(shù)是按哪種方法來(lái)調(diào)用的,請(qǐng)記住一點(diǎn)誰(shuí)調(diào)用這個(gè)函數(shù)或方法關(guān)鍵字就指向誰(shuí)。
本文主要解釋在JS里面this關(guān)鍵字的指向問(wèn)題(在瀏覽器環(huán)境下)。
首先,必須搞清楚在JS里面,函數(shù)的幾種調(diào)用方式:
普通函數(shù)調(diào)用
作為方法來(lái)調(diào)用
作為構(gòu)造函數(shù)來(lái)調(diào)用
使用apply/call方法來(lái)調(diào)用
Function.prototype.bind方法
es6箭頭函數(shù)
但是不管函數(shù)是按哪種方法來(lái)調(diào)用的,請(qǐng)記住一點(diǎn):誰(shuí)調(diào)用這個(gè)函數(shù)或方法,this關(guān)鍵字就指向誰(shuí)。
接下來(lái)就分情況來(lái)討論下這些不同的情況:
普通函數(shù)調(diào)用function person(){ this.name="xl"; console.log(this); console.log(this.name); } person(); //輸出 window xl
在這段代碼中person函數(shù)作為普通函數(shù)調(diào)用,實(shí)際上person是作為全局對(duì)象window的一個(gè)方法來(lái)進(jìn)行調(diào)用的,即window.person();
所以這個(gè)地方是window對(duì)象調(diào)用了person方法,那么person函數(shù)當(dāng)中的this即指window,同時(shí)window還擁有了另外一個(gè)屬性name,值為xl.
var name="xl"; function person(){ console.log(this.name); } person(); //輸出 xl
同樣這個(gè)地方person作為window的方法來(lái)調(diào)用,在代碼的一開(kāi)始定義了一個(gè)全局變量name,值為xl,它相當(dāng)于window的一個(gè)屬性,即window.name="xl",又因?yàn)樵谡{(diào)用person的時(shí)候this是指向window的,因此這里會(huì)輸出xl.
作為方法來(lái)調(diào)用在上面的代碼中,普通函數(shù)的調(diào)用即是作為window對(duì)象的方法進(jìn)行調(diào)用。顯然this關(guān)鍵字指向了window對(duì)象.
再來(lái)看下其他的形式
var name="XL"; var person={ name:"xl", showName:function(){ console.log(this.name); } } person.showName(); //輸出 xl //這里是person對(duì)象調(diào)用showName方法,很顯然this關(guān)鍵字是指向person對(duì)象的,所以會(huì)輸出name var showNameA=person.showName; showNameA(); //輸出 XL //這里將person.showName方法賦給showNameA變量,此時(shí)showNameA變量相當(dāng)于window對(duì)象的一個(gè)屬性,因此showNameA()執(zhí)行的時(shí)候相當(dāng)于window.showNameA(),即window對(duì)象調(diào)用showNameA這個(gè)方法,所以this關(guān)鍵字指向window
再換種形式:
var personA={ name:"xl", showName:function(){ console.log(this.name); } } var personB={ name:"XL", sayName:personA.showName } personB.sayName(); //輸出 XL //雖然showName方法是在personA這個(gè)對(duì)象中定義,但是調(diào)用的時(shí)候卻是在personB這個(gè)對(duì)象中調(diào)用,因此this對(duì)象指向作為構(gòu)造函數(shù)來(lái)調(diào)用
function Person(name){ this.name=name; } var personA=Person("xl"); console.log(personA.name); // 輸出 undefined console.log(window.name);//輸出 xl //上面代碼沒(méi)有進(jìn)行new操作,相當(dāng)于window對(duì)象調(diào)用Person("xl")方法,那么this指向window對(duì)象,并進(jìn)行賦值操作window.name="xl". var personB=new Person("xl"); console.log(personB.name);// 輸出 xl //這部分代碼的解釋見(jiàn)下new操作符
//下面這段代碼模擬了new操作符(實(shí)例化對(duì)象)的內(nèi)部過(guò)程 function person(name){ var o={}; o.__proto__=Person.prototype; //原型繼承 Person.call(o,name); return o; } var personB=person("xl"); console.log(personB.name); // 輸出 xl
在person里面首先創(chuàng)建一個(gè)空對(duì)象o,將o的proto指向Person.prototype完成對(duì)原型的屬性和方法的繼承
Person.call(o,name)這里即函數(shù)Person作為apply/call調(diào)用(具體內(nèi)容下方),將Person對(duì)象里的this改為o,即完成了o.name=name操作
返回對(duì)象o。
因此`person("xl")`返回了一個(gè)繼承了`Person.prototype`對(duì)象上的屬性和方法,以及擁有`name`屬性為"xl"的對(duì)象,并將它賦給變量`personB`. 所以`console.log(personB.name)`會(huì)輸出"xl"call/apply方法的調(diào)用
在JS里函數(shù)也是對(duì)象,因此函數(shù)也有方法。從Function.prototype上繼承到Function.prototype.call/Function.prototype.apply方法
call/apply方法最大的作用就是能改變this關(guān)鍵字的指向.
Obj.method.apply(AnotherObj,arguments);
var name="XL"; var Person={ name:"xl", showName:function(){ console.log(this.name); } } Person.showName.call(); //輸出 "XL" //這里call方法里面的第一個(gè)參數(shù)為空,默認(rèn)指向window。 //雖然showName方法定義在Person對(duì)象里面,但是使用call方法后,將showName方法里面的this指向了window。因此最后會(huì)輸出"XL";
funtion FruitA(n1,n2){ this.n1=n1; this.n2=n2; this.change=function(x,y){ this.n1=x; this.n2=y; } } var fruitA=new FruitA("cheery","banana"); var FruitB={ n1:"apple", n2:"orange" }; fruitA.change.call(FruitB,"pear","peach"); console.log(FruitB.n1); //輸出 pear console.log(FruitB.n2);// 輸出 peach
FruitB調(diào)用fruitA的change方法,將fruitA中的this綁定到對(duì)象FruitB上。
Function.prototype.bind()方法var name="XL"; function Person(name){ this.name=name; this.sayName=function(){ setTimeout(function(){ console.log("my name is "+this.name); },50) } } var person=new Person("xl"); person.sayName() //輸出 “my name is XL”; //這里的setTimeout()定時(shí)函數(shù),相當(dāng)于window.setTimeout(),由window這個(gè)全局對(duì)象對(duì)調(diào)用,因此this的指向?yàn)閣indow, 則this.name則為XL
那么如何才能輸出"my name is xl"呢?
var name="XL"; function Person(name){ this.name=name; this.sayName=function(){ setTimeout(function(){ console.log("my name is "+this.name); }.bind(this),50) //注意這個(gè)地方使用的bind()方法,綁定setTimeout里面的匿名函數(shù)的this一直指向Person對(duì)象 } } var person=new Person("xl"); person.sayName(); //輸出 “my name is xl”;
這里setTimeout(function(){console.log(this.name)}.bind(this),50);,匿名函數(shù)使用bind(this)方法后創(chuàng)建了新的函數(shù),這個(gè)新的函數(shù)不管在什么地方執(zhí)行,this都指向的Person,而非window,因此最后的輸出為"my name is xl"而不是"my name is XL"
另外幾個(gè)需要注意的地方:
setTimeout/setInterval/匿名函數(shù)執(zhí)行的時(shí)候,this默認(rèn)指向window對(duì)象,除非手動(dòng)改變this的指向。在《javascript高級(jí)程序設(shè)計(jì)》當(dāng)中,寫(xiě)到:“超時(shí)調(diào)用的代碼(setTimeout)都是在全局作用域中執(zhí)行的,因此函數(shù)中的this的值,在非嚴(yán)格模式下是指向window對(duì)象,在嚴(yán)格模式下是指向undefined”。本文都是在非嚴(yán)格模式下的情況。
var name="XL"; function Person(){ this.name="xl"; this.showName=function(){ console.log(this.name); } setTimeout(this.showName,50); } var person=new Person(); //輸出 "XL" //在setTimeout(this.showName,50)語(yǔ)句中,會(huì)延時(shí)執(zhí)行this.showName方法 //this.showName方法即構(gòu)造函數(shù)Person()里面定義的方法。50ms后,執(zhí)行this.showName方法,this.showName里面的this此時(shí)便指向了window對(duì)象。則會(huì)輸出"XL";
修改上面的代碼:
var name="XL"; function Person(){ this.name="xl"; var that=this; this.showName=function(){ console.log(that.name); } setTimeout(this.showName,50) } var person=new Person(); //輸出 "xl" //這里在Person函數(shù)當(dāng)中將this賦值給that,即讓that保存Person對(duì)象,因此在setTimeout(this.showName,50)執(zhí)行過(guò)程當(dāng)中,console.log(that.name)即會(huì)輸出Person對(duì)象的屬性"xl"
匿名函數(shù):
var name="XL"; var person={ name:"xl", showName:function(){ console.log(this.name); } sayName:function(){ (function(callback){ callback(); })(this.showName) } } person.sayName(); //輸出 XL
var name="XL"; var person={ name:"xl", showName:function(){ console.log(this.name); } sayName:function(){ var that=this; (function(callback){ callback(); })(that.showName) } } person.sayName() ; //輸出 "xl" //匿名函數(shù)的執(zhí)行同樣在默認(rèn)情況下this是指向window的,除非手動(dòng)改變this的綁定對(duì)象Eval函數(shù)
該函數(shù)執(zhí)行的時(shí)候,this綁定到當(dāng)前作用域的對(duì)象上
var name="XL"; var person={ name:"xl", showName:function(){ eval("console.log(this.name)"); } } person.showName(); //輸出 "xl" var a=person.showName; a(); //輸出 "XL"箭頭函數(shù)
es6里面this指向固定化,始終指向外部對(duì)象,因?yàn)榧^函數(shù)沒(méi)有this,因此它自身不能進(jìn)行new實(shí)例化,同時(shí)也不能使用call, apply, bind等方法來(lái)改變this的指向
function Timer() { this.seconds = 0; setInterval( () => this.seconds ++, 1000); } var timer = new Timer(); setTimeout( () => console.log(timer.seconds), 3100); // 3 在構(gòu)造函數(shù)內(nèi)部的setInterval()內(nèi)的回調(diào)函數(shù),this始終指向?qū)嵗膶?duì)象,并獲取實(shí)例化對(duì)象的seconds的屬性,每1s這個(gè)屬性的值都會(huì)增加1。否則最后在3s后執(zhí)行setTimeOut()函數(shù)執(zhí)行后輸出的是0參考資料
javascript中this詳解
深入淺出javascript中的this
setTimeout中this的指向問(wèn)題
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85844.html
摘要:出于這個(gè)原因,該函數(shù)返回的,所以在這里指的是,所以返回的是第一個(gè)說(shuō)明關(guān)鍵字通常在對(duì)象的構(gòu)造函數(shù)中使用,用來(lái)引用對(duì)象。重寫(xiě)無(wú)法重寫(xiě),因?yàn)樗且粋€(gè)關(guān)鍵字。結(jié)論,表示當(dāng)前的上下文對(duì)象是一個(gè)對(duì)象,可以調(diào)用對(duì)象所擁有的屬性,方法。 在《javaScript語(yǔ)言精粹》這本書(shū)中,把 this 出現(xiàn)的場(chǎng)景分為四類(lèi),簡(jiǎn)單的說(shuō)就是: 有對(duì)象就指向調(diào)用對(duì)象 沒(méi)調(diào)用對(duì)象就指向全局對(duì)象 用new構(gòu)造就指向新對(duì)...
摘要:本文給大家詳細(xì)介紹了下中關(guān)鍵字的使用方法,以及使用關(guān)鍵字的區(qū)別,有需要的小伙伴可以參考下。第行通過(guò)關(guān)鍵字創(chuàng)建了一個(gè)新對(duì)象行對(duì)象嘗試訪(fǎng)問(wèn)和屬性,并調(diào)用方法。一般情況下,函數(shù)對(duì)象在產(chǎn)生時(shí)會(huì)內(nèi)置屬性并將函數(shù)名作為賦值僅函數(shù)對(duì)象。 本文給大家詳細(xì)介紹了下javascript中new關(guān)鍵字的使用方法,以及javascript 使用new關(guān)鍵字的區(qū)別,有需要的小伙伴可以參考下。 function ...
摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當(dāng)作缺點(diǎn)提及,但是只要善于運(yùn)用,其實(shí)基于原型的繼承模型比傳統(tǒng)的類(lèi)繼承還要強(qiáng)大。中文指南基本操作指南二繼續(xù)熟悉的幾對(duì)方法,包括,,。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 怎樣使用 this 因?yàn)楸救藢儆趥吻岸耍虼宋闹兄豢炊?8 成左右,希望能夠給大家?guī)?lái)幫助....(據(jù)說(shuō)是阿里的前端妹子寫(xiě)的) this 的值到底...
摘要:作為構(gòu)造函數(shù)調(diào)用中沒(méi)有類(lèi),但是可以從構(gòu)造器中創(chuàng)建對(duì)象,并提供了運(yùn)算符來(lái)進(jìn)行調(diào)用該構(gòu)造器。構(gòu)造器的外表跟普通函數(shù)一樣,大部分的函數(shù)都可以當(dāng)做構(gòu)造器使用。如果構(gòu)造函數(shù)顯式的返回一個(gè)對(duì)象,那么則會(huì)指向該對(duì)象。 this 的指向 this 是 js 中定義的關(guān)鍵字,它自動(dòng)定義于每一個(gè)函數(shù)域內(nèi),但是它的指向卻讓人很迷惑。在實(shí)際應(yīng)用中,this 的指向大致可以分為以下四種情況。 1.作為普通函數(shù)調(diào)...
摘要:刪除對(duì)匿名函數(shù)的引用,以便釋放內(nèi)存在匿名函數(shù)從中被返回后,它的作用域鏈被初始化為包含函數(shù)的活動(dòng)對(duì)象和全局變量對(duì)象。閉包與變量我們要注意到,閉包只能取到任意變量的最后值,也就是我們保存的是活動(dòng)對(duì)象,而不是確定值。 工作中會(huì)遇到很多 this對(duì)象 指向不明的問(wèn)題,你可能不止一次用過(guò) _self = this 的寫(xiě)法來(lái)傳遞this對(duì)象,它每每會(huì)讓我們覺(jué)得困惑和抓狂,我們很可能會(huì)好奇其中到底發(fā)...
閱讀 1711·2021-11-23 09:51
閱讀 3265·2021-09-26 10:21
閱讀 828·2021-09-09 09:32
閱讀 911·2019-08-29 16:06
閱讀 3354·2019-08-26 13:36
閱讀 810·2019-08-26 10:56
閱讀 2593·2019-08-26 10:44
閱讀 1171·2019-08-23 14:04