JavaScript 內(nèi)的 this 指向

在 javascript 語言中, 有一個奇奇怪怪的 "關鍵字" 叫做 this為什么說它是 奇奇怪怪 呢, 是因為你寫出 100 個 this, 可能有 100 個解釋, 完全不挨邊,但是, 在你的學習過程中, 搞清楚了 this 這個玩意, 那么會對你的開發(fā)生涯有很大幫助的,接下來咱們就開始一點一點的認識一下 this
this 初認識
看到 this, 先給他翻譯過來 "這個"到底啥意思呢 ?
飯桌上, 你媽和你說, 你多吃點的這個
商店里, 你媳婦和你說, 這個包 這個包 這個包 我都要
宴會上, 你爸和人介紹說, 這個傻小子是我兒子
你看, 每一句話上都有 "這個", 但是每個 "這個" 都是一個意思嗎?并不,就像我們 js 內(nèi)的 this 一樣, 每一個 this 的意思都不一樣,但是我們會發(fā)現(xiàn),在說話的過程中, "這個" 是和我們說話的手勢有關系在 js 內(nèi)一個道理,this 的意思是和代碼的 "手勢" 有關系例子 :
當你媳婦手指著一個 LV 包的時候, 說的 "這個" 指代的就是 LV包
當你媽指著魚香肉絲的時候說 "這個" 指代的就是 魚香肉絲
所以在 javascript 內(nèi)的 this 是要看 "說這句話的代碼手指向哪里了"
看看下面一段代碼
當你點擊 box 這個元素的時候, 會觸發(fā)后面的函數(shù),然后函數(shù)一執(zhí)行, 就會在控制臺打印一下 this,這里的 this 就是 box 這個元素,這就是一個非常簡單的 this 指向的例子了
接下來我們就開始詳細學習一下 this
給你個概念?,?this , 是一個指針形變量, 它動態(tài)的指向當前函數(shù)的運行環(huán)境,"什么鬼東西, 我聽不懂啊",給一個私人的解釋 : "根據(jù) this 所在的函數(shù)是如何被調(diào)用的來決定 this 是什么"
舉個例子來看一下
因為 this 是在 fn 函數(shù)內(nèi), 所以 fn 函數(shù)的調(diào)用方式就決定了這個 this 是什么
因為 this 是在 b 函數(shù)內(nèi), 所以 b 函數(shù)的調(diào)用方式?jīng)Q定了 this 是什么, 和 a 函數(shù)沒關系,就是這個意思,最后, 根據(jù)這些年的經(jīng)驗總結給出一個私人的概念, 要牢記
函數(shù)的 this
和函數(shù)定義在哪沒關系
和函數(shù)怎么定義沒關系
只看這個函數(shù)的調(diào)用方式
箭頭函數(shù)除外
對象調(diào)用對象調(diào)用, 就是利用一個對象作為宿主來調(diào)用函數(shù)最簡單的方式就是把函數(shù)寫在一個對象內(nèi), 利用對象來調(diào)用
這時候, 我們調(diào)用了和這個對象內(nèi)的 fn 函數(shù)
調(diào)用方式就是利用對象調(diào)用的函數(shù), 所以在這個函數(shù)內(nèi)的 this 就是 obj 這個對象,換句話說, 只要在這個函數(shù)內(nèi), 只要出現(xiàn) this 就是這個對象
全局調(diào)用
顧名思義, 全局調(diào)用就是直接調(diào)用一個全局函數(shù)
此時這個函數(shù)內(nèi)的 this 就是 window,可能有的小伙伴覺得瘋了,但是我們仔細思考一下, 你會發(fā)現(xiàn),其實 fn 因為是在全局上的, 那么其實調(diào)用的完整寫法可以寫成 window.fn(),此時就回到了之前對象調(diào)用那條路上, 這樣就通順了
奇怪的調(diào)用
這個時候, 有的小伙伴可能會想到一個問題, 如果這個函數(shù)不放在全局呢 ?
此時的 this 應該是什么呢 ?
按照之前的思路思考,○ obj.fn() 確實調(diào)用了函數(shù), 但是 this 不是在 obj.fn 函數(shù)內(nèi), 是在 fun 函數(shù)內(nèi),○ fun() 確實也調(diào)用了函數(shù), 但是我沒有辦法寫成 window.fun(),○ 那么 this 到底是不是 window 呢, 還是應該是 obj 內(nèi)
答案確實是 window, 這又是為什么呢 ?
捋一下思路
說到這里, 我們會發(fā)現(xiàn),this 真的是好奇怪哦 o( ̄︶ ̄)o 搞不定了,要是按照這個方式, 我來回來去的得記多少種, 誰會記得下來呢
接下來(劃重點)
我用寫代碼三十年的經(jīng)驗給你總結出來了一些內(nèi)容, 希望你能牢記
this 的個人經(jīng)驗
首先, this 在各種不同的情況下會不一樣,那么從現(xiàn)在開始我把我總結的內(nèi)容毫無保留的傳授給你
經(jīng)驗一 :
在 js 的非嚴格模式下適用
在非箭頭函數(shù)中適用
不管函數(shù)定義在哪, 不管函數(shù)怎么定義, 只看函數(shù)的調(diào)用方式
只要我想知道 this 是誰
就看這個 this 是寫在哪個函數(shù)里面
這個函數(shù)是怎么被調(diào)用的
觀察 this 在哪個函數(shù)內(nèi)
一定要注意 : 你想知道的 this 在哪個函數(shù)內(nèi), 就去觀察哪個函數(shù)的調(diào)用方式就好了一些常見的函數(shù)調(diào)用方式
普通調(diào)用
調(diào)用方式 : 函數(shù)名()
this 是 window
只要你書寫 "函數(shù)名()" 調(diào)用了一個函數(shù), 那么這個函數(shù)內(nèi)的 this 就是 window
2,對象調(diào)用
調(diào)用方式:
對象.函數(shù)名()
對象'函數(shù)名'
this 就是這個對象, 對象叫啥, 函數(shù)內(nèi)的 this 就叫啥
3,定時器調(diào)用
調(diào)用方式
setTimeout(function () {}, 1000)
setInterval(function () {}, 1000)
this 就是 window
一個函數(shù)不管是怎么定義的, 只要被當做定時器處理函數(shù)使用, this 就是 widnow
4,事件處理函數(shù)
調(diào)用方式
事件源.on事件類型 = 事件處理函數(shù)
事件源.addEventListener(事件類型, 事件處理函數(shù))
this 就是 事件源
只要是作為事件處理函數(shù)使用, 那么該函數(shù)內(nèi)的 this 就是 事件源奧,對了,事件就是:在事件中,當前操作的那個元素就是事件源
5,構造函數(shù)調(diào)用
調(diào)用方式
new 函數(shù)名()
this 就是該構造函數(shù)的當前實例
只要和 new 關鍵字調(diào)用了, this 就是實例對象
記清楚原則 :
不管函數(shù)在哪定義,不管函數(shù)怎么定義,只看函數(shù)的調(diào)用方式
經(jīng)驗二 :
在嚴格模式下適用,其實只有一個,全局函數(shù)沒有 this, 是 undefined,其他的照搬經(jīng)驗一就可以了
非嚴格模式
2.嚴格模式
記清楚原則 :
嚴格模式下,全局函數(shù)沒有 this,是個 undefiend
經(jīng)驗三 :
專門來說一下箭頭函數(shù),其實也只有一條
推翻之前的所有內(nèi)容,箭頭函數(shù)內(nèi)沒有自己的 this,箭頭函數(shù)內(nèi)的 this 就是外部作用域的 this
換句話說, 當你需要判斷箭頭函數(shù)內(nèi)的 this 的時候,和函數(shù)怎么調(diào)用沒有關系了,要看函數(shù)定義在什么位置
記清楚原則 :
只要是箭頭函數(shù),不管函數(shù)怎么調(diào)用,就看這個函數(shù)定義在了哪里
最后
好了,按照以上三個經(jīng)驗, 記清楚原則,那么在看到 this 就不慌了