關於this指向性的問題

函數調用

首先須要從函數的調用開始講起。瀏覽器

JS(ES5)裏面有三種函數調用形式:app

 

func(p1, p2) 
obj.child.method(p1, p2)
func.call(context, p1, p2) // 先不講 apply



通常,初學者都知道前兩種形式,並且認爲前兩種形式「優於」第三種形式。函數

從看到這篇文章起,你必定要記住,第三種調用形式,纔是正常調用形式:this

func.call(context, p1, p2)

其餘兩種都是語法糖,能夠等價地變爲 call 形式:spa

func(p1, p2) 等價於
func.call(undefined, p1, p2)

obj.child.method(p1, p2) 等價於
obj.child.method.call(obj.child, p1, p2)

請記下來。(咱們稱此代碼爲「轉換代碼」,方便下文引用)code

至此咱們的函數調用只有一種形式:對象

func.call(context, p1, p2)

這樣,this 就好解釋了

this,就是上面代碼中的 context。就這麼簡單。io

this 是你 call 一個函數時傳的 context,因爲你歷來不用 call 形式的函數調用,因此你一直不知道。console

先看 func(p1, p2) 中的 this 如何肯定:function

當你寫下面代碼時

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 對象

[ ] 語法

function fn (){ console.log(this) } 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 :) 

 

總結

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

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

完。

相關文章
相關標籤/搜索