this 的值到底是什麼?一次說清楚

2022-09-07 11:21:10 字數 2981 閱讀 4784

方應杭​

杭州飢人谷教育科技**** 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...