用中國話學this指向

這篇文章針對有JS基礎(chǔ),但始終無法搞清楚this指向的同學
如果你知道call和apply以及bind方法,那就再好不過了
你還需要知道漢語當中的,第一人稱和第二人稱以及第三人稱的區(qū)別
先看個新聞
“我體內(nèi)的惡魔已被鎖住了這么多年,現(xiàn)在這種鎖鏈已經(jīng)松了?!?
“我很害怕,很孤獨,很疑惑,我將要向?qū)е?span id="s0sssss00s" class="color-pink-03">我的痛苦的根源——社會作出反擊,我想盡我所能地去傷害這個社會,然后死去。”
這段令人不寒而栗的文字,是美國北達科他州系列殺人案嫌犯約瑟夫·鄧肯于2005年5月11日寫下的。當人們在近兩個月后看到這段文字時,他已經(jīng)將一個 5口之家的3人殘忍地殺害,并綁架了另外2名分別為8歲和9歲的孩子。
假設(shè),你是一個警察,抓到了一個嫌疑犯
然后你在他的家里搜出這本日記,此時你作何感想?
你肯定會想,如果這是嫌疑人自己寫的,這不就等于認罪了嘛?
當然,犯罪嫌疑人也可以狡辯說,這日記根本不是我寫的,只是我從網(wǎng)上摘抄的段子
其實, 我們只需要將上面那段文字稍微做一丟丟的改動, 這份有力的殺人證據(jù),瞬間就會變得不那么有力了
他?體內(nèi)的惡魔已被鎖住了這么多年,現(xiàn)在這種鎖鏈已經(jīng)松了。?他?很害怕,很孤獨,很疑惑,?他?將要向?qū)е?他?的痛苦的根源——社會作出反擊,?他?想盡?他?所能地去傷害這個社會,然后死去。
發(fā)現(xiàn)沒有??? ? 僅僅只是把第一人稱, 改為了第三人稱。
你很難因為這個而定嫌疑犯的罪。 因為這看上去太像個小說了
為什么會有這樣的差別呢?
帶著對這個問題的思考, 我們來開始今天this指向的學習。

接下來看一段代碼

結(jié)果很容易預(yù)測,打印obj
對象本身
在JS中,this屬于一個關(guān)鍵字,也就是可以理解為,它是一個系統(tǒng)自帶命令
通常,我們把它的含義解釋為:當前對象
那么問題來了: 當前對象到底是指誰呢?
在上面的代碼案例中,this代表的就是obj
這個對象
接下來我們再看一段代碼

結(jié)果打印window
對象
如果你對這個打印結(jié)果感到奇怪,那么可能你忽略了一個常識問題
window對象是可以省略不寫的!
所以,上面的代碼,實際上等價于:

我們再來看一個常見的例子,關(guān)于事件綁定

最終,無論是手動調(diào)用,還是單擊鼠標瀏覽器自動調(diào)用
打印結(jié)果都是btn
對象

我們似乎總結(jié)出了一個this指向的規(guī)律
this總是指向,調(diào)用函數(shù)的對象
如果你的代碼結(jié)構(gòu)是這樣的??

那么,函數(shù)里的this,必然指向這個對象本身
假設(shè)這個結(jié)論是成立的, 我們不妨來驗證一下我們的猜想??!

從上面代碼的例子中,可以看出來
window
對象和obj1
對象和obj2
對象,共享了一個函數(shù)?show

三個對象,用了同一個函數(shù)
但打印出的this是各不相同的
window.show();
打印出window對象
obj1.show1();
打印出obj1對象
obj2.show2();
打印出obj2對象
這似乎再一次印證了,我們剛才的猜想:?
函數(shù)由哪個對象調(diào)用,this就指向哪個對象

科學是嚴謹?shù)?,得出結(jié)論之前,我們還是要反復(fù)驗證
再看一個例子:

實際上,我只是在原來代碼的基礎(chǔ)上,增加了一個延遲器,并且時間設(shè)為0
那么打印出的this會不會有變化呢??你可以先思考一番。
通常按照直覺,我們會認為,延遲器只是延緩了執(zhí)行時間,打印結(jié)果依然還是btn對象,沒有變化
但經(jīng)過測試發(fā)現(xiàn),實際的打印結(jié)果,是?window
對象
是我們剛才的猜想錯了嗎?
要解釋這個現(xiàn)象,我們得重新來觀察這段代碼

注意代碼當中出現(xiàn)了兩個函數(shù),我們分別起名字叫做函數(shù)A和函數(shù)B
按照我們剛才的猜想:?函數(shù)由哪個對象調(diào)用,this就指向哪個對象
所以,this指向會依賴它所在的函數(shù)
而這個函數(shù),到底是 函數(shù)A
還是函數(shù)B
呢?
其實你不難從代碼中看的出來,?this
很明顯是在函數(shù)B
中的
所以, 結(jié)果沒有打印出?btn
, 現(xiàn)在我們也不感到奇怪了
因為,?this
已經(jīng)不再函數(shù)?A
的內(nèi)部了,而是函數(shù)B
的內(nèi)部
你可能還要問,為什么函數(shù)B
里的this
指向window
呢?
這里其實算是一個特例,傳入定時器的函數(shù),由哪個對象調(diào)用,我們不得而知
這種情況,this
通通指向window
你暫時記住這個規(guī)律就好了,等你學完了作用域鏈,你就會明白其中的本質(zhì)

回到我們開頭的新聞
假設(shè)日記就是嫌疑人寫的。 但日記里全是第三人稱。那么 "他" 到底是誰就很難說了
反過來如果日記里用的都是第一人稱寫的。 那么 "我" 肯定指的是嫌疑人自己
JS函數(shù)當中的this
關(guān)鍵字, 就相當于我們說話中的第一人稱代詞我
例如這樣一個例子:
A對B說:“我要殺了你!”
這里的我指代A, 你 指代B
B對A說:”我要弄死你!”
這里的我指代B, 你 指代A
所以你看,同樣的一個字,它可以指代任何人,關(guān)鍵看從誰的嘴里說出來


到目前為止,我們差不多可以得出結(jié)論了,下面用幾個練習最終驗證一下

上面的代碼,最終打印obj
無論經(jīng)過多少曲折,想要搞清楚this指向,我們最終只看一個結(jié)論,那就是:
this所在的函數(shù),由哪個對象調(diào)用?
我把代碼進一步改造

上面的代碼,最終打印還是obj
對象
當然了,也總會有一些例外情況, 比如下面這個:

我們不禁要問,函數(shù)m2是由哪個對象調(diào)用的?
我們想盡了各種可能,最終發(fā)現(xiàn)都是錯的。我們始終不知道這個m2由哪個對象調(diào)用,好像它就那樣執(zhí)行了
而實際的打印結(jié)果呢?
不出意外,還是window
對象
最后的結(jié)論
所有的this關(guān)鍵字,在函數(shù)運行時,才能確定它的指向
this所在的函數(shù)由哪個對象調(diào)用,this就會指向誰
當函數(shù)執(zhí)行時,沒有明確的調(diào)用對象時,則this指向window

剛才遺留了一個問題沒有解決

我們期待this指向btn,而this現(xiàn)在卻指向了window
這個問題該怎么修復(fù)呢? 有很多辦法
如果你不知道call、apply、bind,那么恐怕你只能看得懂方法A




接下來的內(nèi)容,學完ES6的箭頭函數(shù)再來吧
1. 如何判斷箭頭函數(shù)的this?
因為箭頭函數(shù)不具備自己的this,所以非常簡單,假裝它不存在,就像這樣:

這下this的指向非常清晰了吧
2. 箭頭函數(shù)可以用call來改變this指向嗎?
不能??! 試圖改變箭頭函數(shù)的this是徒勞的。


構(gòu)造函數(shù)
1. 什么是構(gòu)造函數(shù)?
假設(shè)有一個函數(shù)Fn, 我們有兩種方式來調(diào)用它
普通的調(diào)用?
Fn()
配合
new
關(guān)鍵字來調(diào)用?new Fn()
第二種調(diào)用方式, 函數(shù)就變成了構(gòu)造函數(shù)
注意
,在構(gòu)造函數(shù)中, 上面我們所講的結(jié)論,是不成立的!!
2. 那構(gòu)造函數(shù)里的this是誰呢?
請期待下一篇文章《構(gòu)造函數(shù)與class》