js中this的指(zhi)向(xiang)
時間(jian):2018-09-27 來源(yuan):未(wei)知
近(jin)段時間有很(hen)多同學或是朋(peng)友在問我js中的(de)this的(de)代表的(de)什么?怎么有時能調(diao)用得到有時卻發(fa)現(xian)是undefined,或是調(diao)用交叉錯誤?其實這個問題(ti)呢(ni),以前我也寫(xie)過(guo)有關(guan)(guan)this調(diao)用時 的(de)指向(xiang)的(de)相關(guan)(guan)文章(zhang),今天(tian)就這個問題(ti)再一次的(de)詳細的(de)分析(xi)。
為什么(me)(me)要學習this?如(ru)(ru)果(guo)你(ni)學過函(han)數式編程(cheng),面向對象(xiang)編程(cheng),那你(ni)肯定知(zhi)道干什么(me)(me)用(yong)的,如(ru)(ru)果(guo)你(ni)沒有學過,那么(me)(me)暫(zan)時可(ke)以不用(yong)看這篇文章(zhang),當然如(ru)(ru)果(guo)你(ni)有興趣也可(ke)以看看,畢竟這是js中(zhong)必(bi)須要掌握的東(dong)西
例子1:
function a(){
var user = "追夢子";
console.log(this.user); //undefined
console.log(this); //Window
}
a();
按照我們上面說的(de)this終(zhong)指向的(de)是調(diao)用它的(de)對(dui)象,這里的(de)函(han)數a實際是被Window對(dui)象所點出來的(de),下面的(de)代(dai)碼就可以證明。
function a(){
var user = "追夢(meng)子";
console.log(this.user); //undefined
console.log(this); //Window
}
window.a();
和上面代碼(ma)一樣吧,其實alert也是(shi)window的一個屬(shu)性,也是(shi)window點出來的。
例子2:
var o = {
user:"追(zhui)夢子",
fn:function(){
console.log(this.user); //追夢子
}
}
o.fn();
這里的(de)(de)this指向(xiang)的(de)(de)是對象(xiang)(xiang)o,因(yin)為你調(diao)用這個(ge)fn是通過(guo)o.fn()執行的(de)(de),那自然(ran)指向(xiang)就是對象(xiang)(xiang)o,這里再次強調(diao)一點,this的(de)(de)指向(xiang)在(zai)函數創(chuang)建的(de)(de)時候是決(jue)定不了的(de)(de),在(zai)調(diao)用的(de)(de)時候才能決(jue)定,誰調(diao)用的(de)(de)就指向(xiang)誰,一定要(yao)搞清楚這個(ge)。
其實例子1和(he)例子2說的并不夠準確,下(xia)面這(zhe)個例子就可以推翻上面的理(li)論。
如果要(yao)徹底的搞(gao)懂(dong)this必須(xu)看接下來的幾個例子(zi)
例子3:
var o = {
user:"追夢子",
fn:function(){
console.log(this.user); //追(zhui)夢子
}
}
window.o.fn();
這(zhe)段代碼和上(shang)面(mian)(mian)的(de)那段代碼幾乎是(shi)(shi)一(yi)樣(yang)的(de),但是(shi)(shi)這(zhe)里(li)(li)的(de)this為什么不是(shi)(shi)指向window,如果按照(zhao)上(shang)面(mian)(mian)的(de)理論,終this指向的(de)是(shi)(shi)調(diao)用它的(de)對象,這(zhe)里(li)(li)先說個而外話,window是(shi)(shi)js中的(de)全局對象,我們創建的(de)變量實際上(shang)是(shi)(shi)給window添加屬性,所以這(zhe)里(li)(li)可(ke)以用window點o對象。
這里先不解釋為什么(me)上(shang)面的那段代碼(ma)this為什么(me)沒(mei)有(you)指向window,我(wo)們再(zai)來看一段代碼(ma)。
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
這里同(tong)樣也是(shi)對象o點出來(lai)的(de)(de)(de),但是(shi)同(tong)樣this并沒有執行(xing)它,那(nei)你(ni)(ni)肯定會(hui)說(shuo)我(wo)(wo)一開始說(shuo)的(de)(de)(de)那(nei)些不就都(dou)是(shi)錯誤的(de)(de)(de)嗎?其實也不是(shi),只是(shi)一開始說(shuo)的(de)(de)(de)不準確,接下(xia)來(lai)我(wo)(wo)將補充一句(ju)話,我(wo)(wo)相信你(ni)(ni)就可以徹底的(de)(de)(de)理解this的(de)(de)(de)指向的(de)(de)(de)問題。
情(qing)況1:如(ru)果一(yi)個函(han)數中(zhong)有(you)this,但是它沒(mei)有(you)被上一(yi)級(ji)的(de)對(dui)象所(suo)調用,那么(me)this指向(xiang)的(de)就是window,這里需(xu)要(yao)說明的(de)是在js的(de)嚴格版中(zhong)this指向(xiang)的(de)不是window,但是我們(men)這里不探討嚴格版的(de)問題,你(ni)想了解可以自行上網查找。
情況2:如果一(yi)個函數(shu)中有(you)this,這(zhe)個函數(shu)有(you)被(bei)上(shang)一(yi)級(ji)的(de)對象所調用(yong),那么this指向的(de)就(jiu)是上(shang)一(yi)級(ji)的(de)對象。
情況3:如果(guo)一(yi)個函(han)數(shu)中(zhong)有this,這(zhe)個函(han)數(shu)中(zhong)包含多(duo)個對象,盡管這(zhe)個函(han)數(shu)是(shi)被外層的對象所調用(yong),this指向的也只是(shi)它上一(yi)級的對象,例子(zi)3可以(yi)證明(ming),如果(guo)不(bu)相信,那么接(jie)下來我們繼續看幾個例子(zi)。
var o = {
a:10,
b:{
// a:12,
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
盡管對象(xiang)b中沒(mei)有(you)屬性a,這個this指(zhi)向(xiang)的也是對象(xiang)b,因(yin)為this只會指(zhi)向(xiang)它的上一級對象(xiang),不管這個對象(xiang)中有(you)沒(mei)有(you)this要的東西。
還有一種比較特殊的情況,例(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();
這里this指向的是window,是不是有些(xie)蒙了?其(qi)實(shi)是因(yin)為你沒有理解一句話,這句話同樣至關(guan)重要。
this永遠指(zhi)向(xiang)的(de)是(shi)(shi)后調(diao)用(yong)(yong)它(ta)的(de)對象,也(ye)就是(shi)(shi)看它(ta)執行(xing)的(de)時候(hou)是(shi)(shi)誰調(diao)用(yong)(yong)的(de),例(li)(li)(li)子4中雖然函數fn是(shi)(shi)被(bei)對象b所(suo)引(yin)用(yong)(yong),但(dan)是(shi)(shi)在將fn賦值(zhi)給變量j的(de)時候(hou)并沒有執行(xing)所(suo)以終指(zhi)向(xiang)的(de)是(shi)(shi)window,這(zhe)和(he)例(li)(li)(li)子3是(shi)(shi)不一樣的(de),例(li)(li)(li)子3是(shi)(shi)直接執行(xing)了(le)fn。
this講(jiang)來講(jiang)去其實就是(shi)那么一(yi)回事(shi),只(zhi)不(bu)過在不(bu)同的(de)情況(kuang)下(xia)指(zhi)向(xiang)的(de)會有些不(bu)同,上面的(de)總結(jie)每(mei)個(ge)地方(fang)都(dou)有些小(xiao)錯誤,也不(bu)能說是(shi)錯誤,而(er)是(shi)在不(bu)同環境下(xia)情況(kuang)就會有不(bu)同,所以(yi)我也沒有辦(ban)法一(yi)次解釋清(qing)楚,只(zhi)能你慢慢地的(de)去體會。
構造函數版this:
function Fn(){
this.user = "追夢子(zi)";
}
var a = new Fn();
console.log(a.user); //追夢(meng)子
這(zhe)(zhe)里之所以對(dui)象(xiang)(xiang)a可以點出函(han)數Fn里面(mian)的(de)(de)user是(shi)因為new關(guan)(guan)鍵(jian)字(zi)可以改變this的(de)(de)指(zhi)向(xiang),將這(zhe)(zhe)個(ge)(ge)this指(zhi)向(xiang)對(dui)象(xiang)(xiang)a,為什(shen)么(me)我說a是(shi)對(dui)象(xiang)(xiang),因為用(yong)(yong)了(le)(le)new關(guan)(guan)鍵(jian)字(zi)就是(shi)創(chuang)建一(yi)個(ge)(ge)對(dui)象(xiang)(xiang)實(shi)例,理解這(zhe)(zhe)句話可以想想我們的(de)(de)例子3,我們這(zhe)(zhe)里用(yong)(yong)變量(liang)a創(chuang)建了(le)(le)一(yi)個(ge)(ge)Fn的(de)(de)實(shi)例(相當于復制(zhi)了(le)(le)一(yi)份(fen)Fn到對(dui)象(xiang)(xiang)a里面(mian)),此(ci)時僅僅只是(shi)創(chuang)建,并(bing)沒(mei)有執行,而調用(yong)(yong)這(zhe)(zhe)個(ge)(ge)函(han)數Fn的(de)(de)是(shi)對(dui)象(xiang)(xiang)a,那么(me)this指(zhi)向(xiang)的(de)(de)自然是(shi)對(dui)象(xiang)(xiang)a,那么(me)為什(shen)么(me)對(dui)象(xiang)(xiang)Fn中(zhong)會有user,因為你(ni)已(yi)經復制(zhi)了(le)(le)一(yi)份(fen)Fn函(han)數到對(dui)象(xiang)(xiang)a中(zhong),用(yong)(yong)了(le)(le)new關(guan)(guan)鍵(jian)字(zi)就等同于復制(zhi)了(le)(le)一(yi)份(fen)。
除了上面(mian)的(de)(de)(de)這些以外,我們(men)還可以自行(xing)改變this的(de)(de)(de)指向,關于自行(xing)改變this的(de)(de)(de)指向請看JavaScript中call,apply,bind方法的(de)(de)(de)總結(jie)這篇文章(zhang),詳細的(de)(de)(de)說明了我們(men)如何手動更改this的(de)(de)(de)指向。
更(geng)新一個小問題當this碰(peng)到return時
function fn()
{
this.user = '追夢子';
return {};
}
var a = new fn;
console.log(a.user); //undefined
再看一個
function fn()
{
this.user = '追夢子';
return function(){};
}
var a = new fn;
console.log(a.user); //undefined
再來
function fn()
{
this.user = '追夢(meng)子(zi)';
return 1;
}
var a = new fn;
console.log(a.user); //追夢子
function fn()
{
this.user = '追夢(meng)子';
return undefined;
}
var a = new fn;
console.log(a.user); //追夢(meng)子(zi)
什么意思呢?
如(ru)果返回(hui)值是(shi)一(yi)個(ge)對象(xiang)(xiang),那么this指(zhi)向的(de)就(jiu)是(shi)那個(ge)返回(hui)的(de)對象(xiang)(xiang),如(ru)果返回(hui)值不是(shi)一(yi)個(ge)對象(xiang)(xiang)那么this還是(shi)指(zhi)向函數的(de)實例。
function fn()
{
this.user = '追夢子';
return undefined;
}
var a = new fn;
console.log(a); //fn {user: "追(zhui)夢子"}
還(huan)有一點就是(shi)(shi)雖然null也是(shi)(shi)對象(xiang),但是(shi)(shi)在(zai)這里this還(huan)是(shi)(shi)指向那(nei)個函數(shu)的實(shi)例,因為null比較(jiao)特殊(shu)。
function fn()
{
this.user = '追夢子';
return null;
}
var a = new fn;
console.log(a.user); //追夢子
知識點補充:
1.在嚴(yan)格版中(zhong)的默認的this不再是(shi)window,而是(shi)undefined。
2.new操作符會改變(bian)函數this的(de)指向問題,雖然我們上面講解過了,但是并沒有(you)深入的(de)討(tao)論這個問題,網(wang)上也很少說(shuo),所(suo)以在這里(li)有(you)必要(yao)說(shuo)一下。
function fn(){
this.num = 1;
}
var a = new fn();
console.log(a.num); //1
為什么(me)this會指向a?
因為new關鍵(jian)字會做這三件事情:1:首(shou)先會創建一個空的對(dui)象(xiang)
2:然后會(hui)自動調用apply(繼承(cheng))方法,會(hui)把fn中的屬(shu)性或方法復制到空(kong)對象中
3:后var a =new fn()相當于(yu)var a={};

