原載於前端開發指南,喜歡請關注。javascript
你可能遇到過這樣的 JS 面試題:前端
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window複製代碼
請解釋最後兩行函數的值爲何不同。java
初學者關於 this 的理解一直很模糊。今天這篇文章就要一次講清楚了。面試
並且這個解釋,你在別的地方看不到。看懂這篇文章,全部關於 this 的面試題,都是小菜。瀏覽器
首先須要從函數的調用開始講起。app
JS(ES5)裏面有三種函數調用形式:函數
func(p1, p2)
obj.child.method(p1, p2)
func.call(context, p1, p2) // 先不講 apply複製代碼
通常,初學者都知道前兩種形式,並且認爲前兩種形式「優於」第三種形式。
從看到這篇文章起,你必定要記住,第三種調用形式,纔是正常調用形式:post
func.call(context, p1, p2)複製代碼
其餘兩種都是語法糖,能夠等價地變爲 call 形式:ui
func(p1, p2) 等價於
func.call(undefined, p1, p2)
obj.child.method(p1, p2) 等價於
obj.child.method.call(obj.child, p1, p2)複製代碼
請記下來。(咱們稱此代碼爲「轉換代碼」,方便下文引用)this
至此咱們的函數調用只有一種形式:
func.call(context, p1, p2)複製代碼
this,就是上面代碼中的 context。就這麼簡單。
this 是你 call 一個函數時傳的 context,因爲你歷來不用 call 形式的函數調用,因此你一直不知道。
先看 func(p1, p2) 中的 this 如何肯定:
當你寫下面代碼時
function func(){
console.log(this)
}
func()複製代碼
等價於
function func(){
console.log(this)
}
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 = {
foo: function(){
console.log(this)
}
}
obj.foo()複製代碼
按照「轉換代碼」,咱們將 obj.foo() 轉換爲
obj.foo.call(obj)複製代碼
好了,this 就是 obj。搞定。
回到題目:
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo() // 轉換爲 obj.foo.call(obj),this 就是 obj
bar()
// 轉換爲 bar.call()
// 因爲沒有傳 context
// 因此 this 就是 undefined
// 最後瀏覽器給你一個默認的 this —— window 對象複製代碼
之後你遇到全部跟 this 有關的筆試題,都不會有疑問了。
完。
更多精彩教程,請加入前端 7 羣:369325292
P.S.
使用 new 時,狀況又不同,能夠看個人另外一篇文章《JS 的 new 究竟是幹什麼的?》。