this 的值究竟是什麼?一次說清楚

原載於前端開發指南,喜歡請關注。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 就好解釋了

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 對象複製代碼

總結

  1. this 就是你 call 一個函數時,傳入的 context。
  2. 若是你的函數調用形式不是 call 形式,請按照「轉換代碼」將其轉換爲 call 形式。

之後你遇到全部跟 this 有關的筆試題,都不會有疑問了。

完。

更多精彩教程,請加入前端 7 羣:369325292

P.S.

使用 new 時,狀況又不同,能夠看個人另外一篇文章《JS 的 new 究竟是幹什麼的?》。

相關文章
相關標籤/搜索