理解JavaScript中的this
本文基本是對(duì)
的翻譯整理。好像B站不讓加入站外鏈接,想看原文自己搜去吧。另外吐槽一下原文寫得其實(shí)很亂,只能盡量整理了。
不過其實(shí)this也不是什么難點(diǎn),本文只是記錄一下,萬一哪天有知識(shí)點(diǎn)忘了可以盡快復(fù)習(xí)。
B站你什么時(shí)候才能支持markdown啊
在js使用者中,常有人抱怨this
的語義令人困惑。理解核心函數(shù)調(diào)用原語,并將所有其他調(diào)用函數(shù)的方式視為該原語之上的語法糖,可以消除這種困惑(ES規(guī)范就是這樣理解的)。
本文去掉了一些原文中關(guān)于ES5的額外表述,基于ES6規(guī)范進(jìn)行整理。

核心原語
首先關(guān)注核心函數(shù)調(diào)用原語,一個(gè)Function的call
方法,call方法相對(duì)來說很直接:
從第一個(gè)參數(shù)開始到最后一個(gè)參數(shù)結(jié)束,構(gòu)建一個(gè)參數(shù)列表
argList
第一個(gè)參數(shù)是
thisValue
以
thisValue
作為this
,argList
作為參數(shù)列表調(diào)用該函數(shù)(如果熟悉python的話,可以嘗試結(jié)合python的decorator去理解)
例:
如上面代碼所描述,通過將this
設(shè)置為Yehuda
,以及一個(gè)單獨(dú)的參數(shù)thing
,來調(diào)用hello
方法。這就是js的函數(shù)調(diào)用原語。
簡(jiǎn)單的函數(shù)調(diào)用
顯然上述用call
調(diào)用函數(shù)的方式并不算實(shí)用,js允許以hello("world")
的方式進(jìn)行函數(shù)調(diào)用,當(dāng)我們這樣做的時(shí)候,相當(dāng)于:
概括地說,一個(gè)通過fn(...args)
方式調(diào)用的函數(shù),與fn.call(window [ES5-strict: undefined], ...args)
是等價(jià)的。
看懂這句話后面不用看了,這文章核心內(nèi)容就這一句,后面是bind、apply這些東西,不如翻MDN去

成員函數(shù)調(diào)用
函數(shù)經(jīng)常被作為一個(gè)object的成員進(jìn)行調(diào)用,在這種情況下:
上例中,hello
是如何綁定到一個(gè)object上是無關(guān)緊要的:

使用Function.prototype.bind
進(jìn)行調(diào)用
以前人們經(jīng)常通過閉包方式取巧地將函數(shù)的this值固定:
有了bind之后可以將上述內(nèi)容改為更通用的寫法:
為了理解上述寫法,只需要明確以下兩點(diǎn):
arguments
是一個(gè)類似數(shù)組的object,表示所有傳遞給函數(shù)的參數(shù)apply
工作原理和call
原語一致,唯一區(qū)別在于apply
把所有參數(shù)打包在一起(arguments)接收,call
是一個(gè)個(gè)參數(shù)單獨(dú)接收bind
方法返回一個(gè)新函數(shù),當(dāng)它被調(diào)用,新函數(shù)簡(jiǎn)單地調(diào)用傳入的原始函數(shù)(person.hello
),將原始值設(shè)置為this
,其他參數(shù)照常傳遞。由于
bind
常被使用,ES5在Function
對(duì)象上實(shí)現(xiàn)了bind
,上例可以改為:

沒了