理解(jie)js中this的(de)指向問題(ti)
時間:2018-09-26 來源:未知
在前端的(de)(de)(de)飛速發展的(de)(de)(de)過程中,各種框架層出不(bu)窮(qiong),但是當大家看(kan)到(dao)(dao)這(zhe)些框架的(de)(de)(de)源碼時,大家也許(xu)會發現很(hen)多框架都有(you)this 這(zhe)個(ge)問題,由此(ci)看(kan)來this的(de)(de)(de)指向(xiang)是多么的(de)(de)(de)重(zhong)要,但是關于this問題許(xu)多人對于他的(de)(de)(de)指向(xiang)問題一直都是很(hen)模糊(hu),那么就讓(rang)我(wo)們來一起看(kan)一下this的(de)(de)(de)指向(xiang)到(dao)(dao)底是怎么樣的(de)(de)(de)。
首(shou)先必須(xu)要說(shuo)的(de)是(shi)(shi),this的(de)指(zhi)(zhi)向在函數定(ding)義的(de)時候是(shi)(shi)確定(ding)不(bu)了(le)的(de),只有函數執(zhi)行的(de)時候才能(neng)確定(ding)this到底指(zhi)(zhi)向誰,實際上this的(de)終指(zhi)(zhi)向的(de)是(shi)(shi)那個調用它的(de)對象(這句話(hua)有些問(wen)題,后面會解釋(shi)為(wei)什(shen)么會有問(wen)題,雖(sui)然網上大部分的(de)文章都(dou)是(shi)(shi)這樣說(shuo)的(de),雖(sui)然在很(hen)多情況下那樣去理(li)解不(bu)會出什(shen)么問(wen)題,但是(shi)(shi)實際上那樣理(li)解是(shi)(shi)不(bu)準確的(de),所以在你理(li)解this的(de)時候會有種琢磨不(bu)透(tou)的(de)感覺),那么接下來(lai)我會深(shen)入(ru)的(de)探討(tao)這個問(wen)題。
為什么要學(xue)(xue)習this?如果你學(xue)(xue)過函數式編(bian)程,面向對(dui)象編(bian)程,那你肯定知道干什么用(yong)(yong)的,如果你沒有(you)學(xue)(xue)過,那么暫時(shi)可以不用(yong)(yong)看這篇文(wen)章(zhang),當然(ran)如果你有(you)興趣(qu)也(ye)可以看看,畢竟這是(shi)js中必須(xu)要掌握的東西。
例子1:
function a(){
var user = "飛翔的企鵝“
console.log(this.user); //undefined
console.log(this); //Window
}
a();
按照我們上面說的this終指(zhi)向的是(shi)(shi)調用它的對(dui)象(xiang),這里的函數a實際是(shi)(shi)被Window對(dui)象(xiang)所點出來的,下面的代碼就(jiu)可以證明。
function a(){
var user = "飛翔(xiang)的企鵝“
console.log(this.user); //undefined
console.log(this); //Window
}
window.a();
和上面代碼(ma)一樣吧,其實(shi)alert也(ye)是(shi)window的一個屬性,也(ye)是(shi)window點出來的。
例子2:
var o = {
user:" 飛翔的企鵝",
fn:function(){
console.log(this.user); //飛翔的企鵝
}
}
o.fn();
這里(li)的this指(zhi)向(xiang)的是對象o,因為你調(diao)用(yong)這個fn是通過(guo)o.fn()執行的,那自然指(zhi)向(xiang)就是對象o,這里(li)再次強調(diao)一(yi)點(dian),this的指(zhi)向(xiang)在(zai)函數創建的時(shi)候(hou)是決定(ding)(ding)不了的,在(zai)調(diao)用(yong)的時(shi)候(hou)才(cai)能決定(ding)(ding),誰調(diao)用(yong)的就指(zhi)向(xiang)誰,一(yi)定(ding)(ding)要搞清楚這個。
其實例子1和(he)例子2說的并(bing)不夠準確,下(xia)面這個例子就可以推(tui)翻上面的理論。
如(ru)果要徹底的搞(gao)懂this必須看(kan)接下(xia)來的幾個例子
例子3:
var o = {
user:" 飛翔的企鵝",
fn:function(){
console.log(this.user); //飛(fei)翔(xiang)的企(qi)鵝(e)
}
}
window.o.fn();
這段代碼(ma)和上(shang)面的(de)那段代碼(ma)幾(ji)乎是(shi)一(yi)樣的(de),但(dan)是(shi)這里的(de)this為什么不是(shi)指(zhi)向window,如果按(an)照上(shang)面的(de)理論,終this指(zhi)向的(de)是(shi)調用它(ta)的(de)對象(xiang),這里先說(shuo)個而外話(hua),window是(shi)js中的(de)全局對象(xiang),我們創(chuang)建的(de)變量實際上(shang)是(shi)給window添加屬性,所以這里可(ke)以用window點o對象(xiang)。
這里先不(bu)解釋為什(shen)么上面的那段(duan)(duan)代碼this為什(shen)么沒有指向window,我們再來(lai)看一段(duan)(duan)代碼。
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
這(zhe)里同樣(yang)也(ye)是(shi)對象(xiang)o點出(chu)來(lai)的(de),但是(shi)同樣(yang)this并沒有執(zhi)行它,那你(ni)肯(ken)定(ding)會說(shuo)我(wo)一(yi)(yi)開始(shi)說(shuo)的(de)那些不(bu)(bu)就都是(shi)錯誤的(de)嗎?其實也(ye)不(bu)(bu)是(shi),只是(shi)一(yi)(yi)開始(shi)說(shuo)的(de)不(bu)(bu)準確,接下來(lai)我(wo)將補充(chong)一(yi)(yi)句話,我(wo)相信你(ni)就可以徹底的(de)理解(jie)this的(de)指向的(de)問(wen)題。
情況1:如果一(yi)個函數中有this,但(dan)是(shi)它沒有被上一(yi)級的對象所調用,那么this指(zhi)向(xiang)的就是(shi)window,這(zhe)里需要說明(ming)的是(shi)在js的嚴格版(ban)中this指(zhi)向(xiang)的不是(shi)window,但(dan)是(shi)我們(men)這(zhe)里不探(tan)討嚴格版(ban)的問(wen)題,你(ni)想了(le)解可以自行(xing)上網查找。
情況2:如(ru)果一(yi)個函(han)數中有this,這個函(han)數有被(bei)上一(yi)級的對象(xiang)所調用,那么(me)this指向的就是上一(yi)級的對象(xiang)。
情況3:如果一個(ge)函(han)數(shu)中有this,這個(ge)函(han)數(shu)中包含多個(ge)對象(xiang),盡(jin)管這個(ge)函(han)數(shu)是被外層的(de)(de)(de)對象(xiang)所調用,this指向(xiang)的(de)(de)(de)也只是它上一級(ji)的(de)(de)(de)對象(xiang),例子(zi)3可(ke)以證明,如果不相信(xin),那么接下來我們繼續看(kan)幾個(ge)例子(zi)。
var o = {
a:10,
b:{
// a:12,
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
盡管(guan)對象(xiang)b中沒有屬性a,這個(ge)this指向(xiang)的(de)也是對象(xiang)b,因(yin)為this只(zhi)會指向(xiang)它的(de)上一(yi)級對象(xiang),不管(guan)這個(ge)對象(xiang)中有沒有this要的(de)東(dong)西(xi)。
還有一種比較特(te)殊(shu)的(de)情況,例(li)子4:
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
這里(li)this指向的是(shi)window,是(shi)不是(shi)有(you)些(xie)蒙了?其實是(shi)因為(wei)你沒有(you)理解一句(ju)話,這句(ju)話同樣至(zhi)關重要。
this永(yong)遠指(zhi)向(xiang)的(de)(de)(de)是(shi)后調用(yong)它(ta)的(de)(de)(de)對(dui)(dui)象(xiang),也就是(shi)看它(ta)執行的(de)(de)(de)時候(hou)是(shi)誰(shui)調用(yong)的(de)(de)(de),例子4中雖然函數(shu)fn是(shi)被對(dui)(dui)象(xiang)b所引用(yong),但是(shi)在將fn賦(fu)值給變量j的(de)(de)(de)時候(hou)并沒有執行所以終指(zhi)向(xiang)的(de)(de)(de)是(shi)window,這和(he)例子3是(shi)不一樣的(de)(de)(de),例子3是(shi)直(zhi)接(jie)執行了fn。
this講(jiang)來講(jiang)去其實就是那(nei)么一回(hui)事,只不(bu)過在不(bu)同(tong)的(de)(de)情況下指向的(de)(de)會(hui)有(you)(you)些(xie)不(bu)同(tong),上面(mian)的(de)(de)總結每(mei)個地方都有(you)(you)些(xie)小(xiao)錯誤,也(ye)不(bu)能說是錯誤,而是在不(bu)同(tong)環境(jing)下情況就會(hui)有(you)(you)不(bu)同(tong),所以我也(ye)沒(mei)有(you)(you)辦法一次解釋清楚,只能你慢慢地的(de)(de)去體(ti)會(hui)。
構造函(han)數版this:
function Fn(){
this.user = "飛(fei)翔的企鵝(e)";
}
var a = new Fn();
console.log(a.user); //飛翔的企鵝
這(zhe)里之(zhi)所以(yi)對象(xiang)a可以(yi)點出(chu)函(han)數(shu)(shu)Fn里面(mian)的(de)user是(shi)因為new關鍵(jian)字(zi)可以(yi)改變(bian)this的(de)指(zhi)(zhi)向(xiang),將(jiang)這(zhe)個(ge)(ge)this指(zhi)(zhi)向(xiang)對象(xiang)a,為什么我(wo)說a是(shi)對象(xiang),因為用(yong)了new關鍵(jian)字(zi)就是(shi)創(chuang)(chuang)(chuang)建(jian)一(yi)個(ge)(ge)對象(xiang)實例(li),理解這(zhe)句話可以(yi)想想我(wo)們(men)(men)的(de)例(li)子3,我(wo)們(men)(men)這(zhe)里用(yong)變(bian)量a創(chuang)(chuang)(chuang)建(jian)了一(yi)個(ge)(ge)Fn的(de)實例(li)(相當于復(fu)制了一(yi)份(fen)Fn到對象(xiang)a里面(mian)),此時僅(jin)僅(jin)只是(shi)創(chuang)(chuang)(chuang)建(jian),并沒有執行,而(er)調(diao)用(yong)這(zhe)個(ge)(ge)函(han)數(shu)(shu)Fn的(de)是(shi)對象(xiang)a,那么this指(zhi)(zhi)向(xiang)的(de)自然(ran)是(shi)對象(xiang)a,那么為什么對象(xiang)Fn中會有user,因為你已(yi)經復(fu)制了一(yi)份(fen)Fn函(han)數(shu)(shu)到對象(xiang)a中,用(yong)了new關鍵(jian)字(zi)就等(deng)同于復(fu)制了一(yi)份(fen)。
除(chu)了上面的(de)(de)這(zhe)(zhe)些以外(wai),我們還可以自行改變this的(de)(de)指向(xiang),關于自行改變this的(de)(de)指向(xiang)請看JavaScript中call,apply,bind方(fang)法的(de)(de)總結這(zhe)(zhe)篇文章,詳細的(de)(de)說明(ming)了我們如何(he)手動更改this的(de)(de)指向(xiang)。
更新一個小問題當this碰到return時
function fn()
{
this.user = '飛翔(xiang)的(de)企鵝';
return {};
}
var a = new fn;
console.log(a.user); //undefined
再看一個
function fn()
{
this.user = '飛翔(xiang)的企鵝';
return function(){};
}
var a = new fn;
console.log(a.user); //undefined
再來
function fn()
{
this.user = '飛翔的企(qi)鵝(e)';
return 1;
}
var a = new fn;
console.log(a.user); //飛翔(xiang)的企鵝(e)
function fn()
{
this.user = '飛(fei)翔(xiang)的(de)企鵝';
return undefined;
}
var a = new fn;
console.log(a.user); //飛翔的(de)企鵝(e)
什么意思呢?
如果返(fan)回(hui)(hui)值(zhi)是(shi)一個(ge)對(dui)象,那么this指(zhi)向的(de)(de)就是(shi)那個(ge)返(fan)回(hui)(hui)的(de)(de)對(dui)象,如果返(fan)回(hui)(hui)值(zhi)不是(shi)一個(ge)對(dui)象那么this還是(shi)指(zhi)向函(han)數的(de)(de)實(shi)例。
function fn()
{
this.user = '飛翔的企鵝';
return undefined;
}
var a = new fn;
console.log(a); //fn {user: "飛翔的企(qi)鵝(e)"}
還有一(yi)點就是雖然null也是對象,但是在(zai)這(zhe)里(li)this還是指向那個函數的實例,因為null比較特殊。
function fn()
{
this.user = '飛翔的企鵝';
return null;
}
var a = new fn;
console.log(a.user); //飛(fei)翔(xiang)的企鵝
知識點補充:
1.在嚴格版中(zhong)的默認的this不再是(shi)window,而是(shi)undefined。
2.new操作符(fu)會(hui)改(gai)變函數(shu)this的(de)指向問題(ti),雖然我們上面(mian)講解過了,但是并沒有深(shen)入的(de)討論這個(ge)問題(ti),網上也很少說,所以在這里有必(bi)要說一(yi)下。
function fn(){
this.num = 1;
}
var a = new fn();
console.log(a.num); //1
為什么this會指向a?首(shou)先new關鍵字(zi)會創建一個(ge)(ge)空(kong)的(de)(de)對象(xiang),然(ran)后會自動調(diao)用一個(ge)(ge)函數apply方法,將this指向這個(ge)(ge)空(kong)對象(xiang),這樣的(de)(de)話函數內(nei)部的(de)(de)this就會被這個(ge)(ge)空(kong)的(de)(de)對象(xiang)替代。
相信現(xian)在大家對于this的(de)指向問題(ti)會有一(yi)個全新(xin)的(de)認識了吧,但是(shi)本(ben)人還是(shi)希望大家在實戰中,來(lai)多多體會this的(de)奇特之處(chu),畢(bi)竟代碼不(bu)是(shi)看出來(lai)的(de),只(zhi)有運(yun)用上了才(cai)會明白,才(cai)會熟練的(de)使用。
理解js中this的指向問(wen)題(ti)
在前端(duan)的(de)(de)飛(fei)速發展的(de)(de)過(guo)程中,各種框(kuang)架(jia)(jia)層(ceng)出不窮,但是(shi)(shi)(shi)當(dang)大(da)家看(kan)到(dao)這些框(kuang)架(jia)(jia)的(de)(de)源(yuan)碼時(shi),大(da)家也許會(hui)發現(xian)很(hen)多框(kuang)架(jia)(jia)都有(you)this 這個問題,由此(ci)看(kan)來this的(de)(de)指向是(shi)(shi)(shi)多么(me)的(de)(de)重要,但是(shi)(shi)(shi)關于(yu)this問題許多人對于(yu)他的(de)(de)指向問題一(yi)直都是(shi)(shi)(shi)很(hen)模(mo)糊,那么(me)就讓我們(men)來一(yi)起看(kan)一(yi)下this的(de)(de)指向到(dao)底是(shi)(shi)(shi)怎么(me)樣的(de)(de)。
首先(xian)必須要說的(de)(de)(de)(de)是(shi)(shi)(shi),this的(de)(de)(de)(de)指向(xiang)在函(han)數定義的(de)(de)(de)(de)時(shi)候(hou)(hou)是(shi)(shi)(shi)確定不(bu)了的(de)(de)(de)(de),只有函(han)數執行(xing)的(de)(de)(de)(de)時(shi)候(hou)(hou)才能確定this到底(di)指向(xiang)誰,實際上(shang)(shang)this的(de)(de)(de)(de)終指向(xiang)的(de)(de)(de)(de)是(shi)(shi)(shi)那(nei)個調用它的(de)(de)(de)(de)對(dui)象(這(zhe)(zhe)句(ju)話(hua)有些問(wen)題,后(hou)面(mian)會(hui)(hui)解(jie)(jie)釋為什(shen)么會(hui)(hui)有問(wen)題,雖(sui)然(ran)網(wang)上(shang)(shang)大部(bu)分的(de)(de)(de)(de)文章都是(shi)(shi)(shi)這(zhe)(zhe)樣(yang)說的(de)(de)(de)(de),雖(sui)然(ran)在很多(duo)情況下那(nei)樣(yang)去(qu)理(li)解(jie)(jie)不(bu)會(hui)(hui)出(chu)什(shen)么問(wen)題,但是(shi)(shi)(shi)實際上(shang)(shang)那(nei)樣(yang)理(li)解(jie)(jie)是(shi)(shi)(shi)不(bu)準(zhun)確的(de)(de)(de)(de),所(suo)以在你理(li)解(jie)(jie)this的(de)(de)(de)(de)時(shi)候(hou)(hou)會(hui)(hui)有種琢(zhuo)磨不(bu)透的(de)(de)(de)(de)感(gan)覺),那(nei)么接下來我(wo)會(hui)(hui)深(shen)入的(de)(de)(de)(de)探討(tao)這(zhe)(zhe)個問(wen)題。
為什么(me)要(yao)學(xue)(xue)習this?如果你(ni)學(xue)(xue)過(guo)函數式編程(cheng),面向(xiang)對象編程(cheng),那你(ni)肯定知道干什么(me)用的,如果你(ni)沒有學(xue)(xue)過(guo),那么(me)暫(zan)時可(ke)以不(bu)用看這篇文章,當(dang)然(ran)如果你(ni)有興趣也可(ke)以看看,畢(bi)竟(jing)這是js中必須(xu)要(yao)掌握的東西。
例子1:
function a(){
var user = "飛(fei)翔的(de)企鵝(e)“
console.log(this.user); //undefined
console.log(this); //Window
}
a();
按照我們上面(mian)說(shuo)的(de)this終指向(xiang)的(de)是調用它的(de)對象,這里的(de)函數a實際是被Window對象所(suo)點出來的(de),下面(mian)的(de)代(dai)碼(ma)就可以證(zheng)明(ming)。
function a(){
var user = "飛翔的企鵝“
console.log(this.user); //undefined
console.log(this); //Window
}
window.a();
和上(shang)面代碼一(yi)(yi)樣吧,其(qi)實alert也(ye)是window的一(yi)(yi)個屬(shu)性,也(ye)是window點(dian)出來的。
例子2:
var o = {
user:" 飛(fei)翔的企鵝",
fn:function(){
console.log(this.user); //飛翔的企(qi)鵝

