JavaScript This函數調用模式理解

以前的理解:this 永遠指向最後調用它的那個對象

var name = "windowsName";
    var a = {
        name: "Cherry",
        fn : function () {
            console.log(this.name);      
        }
    }
   a.fn();// Cherry

    var name = "windowsName";
    var a = {
        name: "Cherry",
        fn : function () {
            console.log(this.name);    
        }
    }

    var f = a.fn;
    f();  //最後調用的是window所以打印出來是windowsName

函數調用模式的不同理解

你可能遇到過這樣的 JS 面試題:

var obj = {
  foo: function(){
    console.log(this)
  }
}

var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window   

請解釋最後兩行函數的值爲什麼不一樣。
函數調用
JS(ES5)裏面有三種函數調用形式:

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

一般,都知道前兩種形式,而且認爲前兩種形式「優於」第三種形式。
但第三種調用形式,纔是正常調用形式:

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 就好解釋了 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 對象了

回到題目:

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 了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章