JavaScript This調用模式的轉化分析

this 永遠指向最後調用它的那個對象

對象a最後調用fn

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

window最後調用fn

這裏是先把fn方法賦值到了全局,而後再執行的,因此this指向全局(window)面試

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

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

下面咱們從新舉一個例子來分析this 永遠指向最後調用它的那個對象的本質windows

用調用模式的轉化來分析

你可能遇到過這樣的 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) 上下文調用模式

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

func.call(context, p1, p2)

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

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 形式的函數調用,因此你一直不知道。io

this 如何肯定

先看 func(p1, p2) 中的 this 如何肯定:
當你寫下面代碼時console

function func(){
  console.log(this)
}

func()

等價於

function func(){
  console.log(this)
}

func.call(undefined) // 能夠簡寫爲 func.call()

按理說打印出來的 this 應該就是 undefined 了吧,可是瀏覽器裏有一條規則:function

若是你傳的 context 就 null 或者 undefined,那麼 window 對象就是默認的 context(嚴格模式下默認 context 是 undefined)

所以上面的打印結果是 window。若是你但願這裏的 this 不是 window,很簡單:func.call(obj) // 那麼裏面的 this 就是 obj 對象了

回到題目

bar() 的調用以下:

  • 轉換爲 bar.call()
  • 因爲沒有傳 context
  • 因此 this 就是 undefined
  • 最後瀏覽器給你一個默認的 this —— window 對象
var obj = {
  foo: function(){
    console.log(this)
  }
}

var bar = obj.foo
obj.foo() // 轉換爲 obj.foo.call(obj),this 就是 obj
bar() // 內部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 了

相關文章
相關標籤/搜索