方應杭
杭州飢人谷教育科技**** cto
1,071 人贊同了該文章
你可能遇到過這樣的 js 面試題:
var obj =
}var bar = obj.foo
obj.foo() // 列印出的 this 是 obj
bar() // 列印出的 this 是 window
請解釋最後兩行函式的值為什麼不一樣。
初學者關於 this 的理解一直很模糊。今天這篇文章就要一次講清楚了。
而且這個解釋,你在別的地方看不到。看懂這篇文章,所有關於 this 的面試題,都是小菜。
有用請點贊。
首先需要從函式的呼叫開始講起。
js(es5)裡面有三種函式呼叫形式:
func(p1, p2)
obj.child.method(p1, p2)
一般,初學者都知道前兩種形式,而且認為前兩種形式「優於」第三種形式。
func.call(context, p1, p2)其他兩種都是語法糖,可以等價地變為 call 形式:
func(p1, p2) 等價於
func.call(undefined, p1, p2)
obj.child.method(p1, p2) 等價於
obj.child.method.call(obj.child, p1, p2)
請記下來。(我們稱此**為「轉換**」,方便下文引用)
至此我們的函式呼叫只有一種形式:
func.call(context, p1, p2)
this,就是上面**中的 context。就這麼簡單。
this 是你 call 乙個函式時傳的 context,由於你從來不用 call 形式的函式呼叫,所以你一直不知道。
先看 func(p1, p2) 中的 this 如何確定:
當你寫下面**時
function func()
func()
用「轉換**」把它轉化一下,得到
function func()
func.call(undefined) // 可以簡寫為 func.call()
按理說列印出來的 this 應該就是 undefined 了吧,但是瀏覽器裡有一條規則:
如果你傳的 context 是 null 或 undefined,那麼 window 物件就是預設的 context(嚴格模式下預設 context 是 undefined)因此上面的列印結果是 window。
如果你希望這裡的 this 不是 window,很簡單:
func.call(obj) // 那麼裡面的 this 就是 obj 物件了
再看 obj.child.method(p1, p2) 的 this 如何確定
var obj =
}obj.foo()
按照「轉換**」,我們將 obj.foo() 轉換為
obj.foo.call(obj)
好了,this 就是 obj。搞定。
回到題目:
var obj =
}var bar = obj.foo
obj.foo() // 轉換為 obj.foo.call(obj),this 就是 obj
bar()
// 轉換為 bar.call()
// 由於沒有傳 context
// 所以 this 就是 undefined
// 最後瀏覽器給你乙個預設的 this —— window 物件
function fn ()
var arr = [fn, fn2]
arr[0]() // 這裡面的 this 又是什麼呢?
我們可以把 arr[0]( ) 想象為arr.0( ),雖然後者的語法錯了,但是形式與轉換**裡的 obj.child.method(p1, p2) 對應上了,於是就可以愉快的轉換了:
arr[0]()
假想為 arr.0()
然後轉換為 arr.0.call(arr)
那麼裡面的 this 就是 arr 了 :)
我不明白為什麼需要討論箭頭函式,實際上箭頭函式裡並沒有 this,如果你在箭頭函式裡看到 this,你直接把它當作箭頭函式外面的 this 即可。外面的 this 是什麼,箭頭函式裡面的 this 就還是什麼,因為箭頭函式本身不支援 this。
有人說「箭頭函式裡面的 this 指向箭頭函式外面的 this」,這很傻,因為箭頭函式內外 this 就是同乙個東西,並不存在什麼指向不指向。
this 就是你 call 乙個函式時,傳入的第乙個引數。(請務必背下來「this 就是 call 的第乙個引數」)
如果你的函式呼叫形式不是 call 形式,請按照「轉換**」將其轉換為 call 形式。
以後你遇到所有跟 this 有關的筆試題,都不會有疑問了。
完。p.s.
使用 new 時,情況又不一樣,可以看另一篇文章《js 的 new 到底是幹什麼的?》。
後續篇《你怎麼還沒搞懂 this? - 知乎專欄》
有人說你怎麼不講 strict mode 呢,strict mode 也會影響 this 呀。我認為 strict mode 只是影響了 context 的預設值而已,你看懂此文稍微看看 strict mode 就懂了。我只講最重要的內容。
有人問箭頭函式,箭頭函式其實跟 this 沒關係,所以如果你在箭頭函式裡面看到 this ,就當作是它外面的函式的 this 即可。
input框中的value值到底是什麼
value 屬性為 input 元素設定值。對於不同的輸入型別,value 屬性的用法也不同 注釋 和 中必須設定 value 屬性。注釋 value 屬性無法與 一同使用。input標籤有很多態別,也就是type,以下是一些常用type的說明 text 文字框,input預設的type,不寫就是這...
python的w 到底是什麼
python 檔案處理的開啟方式有很多種,os.mknod test.txt 建立空檔案 fp open test.txt w 直接開啟乙個檔案,如果檔案不存在則建立檔案 open 模式 w 以寫方式開啟,a 以追加模式開啟 從 eof 開始,必要時建立新檔案 r 以讀寫模式開啟 w 以讀寫模式開啟...
js的arguments到底是什麼
類陣列物件 arguments 總所周知,js是一門相當靈活的語言。當我們在js中在呼叫乙個函式的時候,我們經常會給這個函式傳遞一些引數,js把傳入到這個函式的全部引數儲存在乙個叫做arguments的東西裡面,那麼這到底是什麼東西?在js中萬物皆物件,甚至陣列字串函式都是物件。所以這個叫做argu...