深入淺出this的理解

Vincent.W發表於2017-04-11

this在js中一直是謎一樣的存在著,在面試中也是經常會被問道,接下來總結下我所理解的this
首先引入祕密花園中對this的工作原理,文中指出有五種情況,分別是:

  • 全域性範圍內
this;    //在全域性範圍內使用`this`,它將會指向全域性物件複製程式碼
  • 函式呼叫
foo();    //this指向全域性物件複製程式碼
  • 方法呼叫
test.foo();    //this指向test物件複製程式碼
  • 呼叫建構函式
new foo();    //函式與new一塊使用即建構函式,this指向新建立的物件複製程式碼
  • 顯式的設定this
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]);    //this被設定成bar
foo.call(bar, 1, 2, 3);    //this被設定成bar複製程式碼

從函式呼叫理解this

有這樣一道題

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

var foo = obj.func;
obj.func() //this是obj
foo() //this是window複製程式碼

解釋函式結果為什麼不一樣?

這道題可以從函式呼叫來理解,從我看到的博文中有這樣的解釋,祕密花園中的函式呼叫,方法呼叫,顯式的設定this都屬於函式呼叫,相當於函式呼叫的三種方式,可以寫成

foo(params);
obj.child.foo(params);
foo.call(context, params); //apply同理複製程式碼

而且前兩種都可以寫成第三種形式

foo(params); =>> foo.call(undefined, params);

obj.child.foo(); =>> obj.child.foo.call(obj.child, params);複製程式碼

所以說函式呼叫都是foo.call(context, params)的變體,即函式呼叫只有一種。這樣this的值就是文中的contextthis就是你函式呼叫時傳入的context

舉例程式碼中:

function foo() {
    console.log(this);
}

foo();複製程式碼

當你無法確認this指代的值時,轉化成call形式會更好理解

function foo() {
    console.log(this);
}

foo.call(undefined); //or foo.call();複製程式碼

函式執行結果為window,在瀏覽器中有一條規定,傳入contextnullundefined時,則為全域性物件(window物件);嚴格模式下contextundefined

舉例程式碼中:

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

obj.foo();複製程式碼

轉化為call形式為

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

obj.foo.call(obj);複製程式碼

很明顯,this指代obj。

Event Handler 中的this

btn.addEventListener('click' ,function handler(){
  console.log(this) // 請問這裡的 this 是什麼
})複製程式碼

handler 中的this是什麼?用上面的方法好像沒法轉化了,因為不知道addEventListener內原始碼實現,檢視文件MDN

通常來說this的值是觸發事件的元素的引用,這種特性在多個相似的元素使用同一個通用事件監聽器時非常讓人滿意。

當使用 addEventListener() 為一個元素註冊事件的時候,控制程式碼裡的 this 值是該元素的引用。其與傳遞給控制程式碼的 event 引數的 currentTarget 屬性的值一樣。

所以可以假設瀏覽器addEventListener是這樣實現的

// 當事件被觸發時
handler.call(event.currentTarget, event) // this => event.currentTarget複製程式碼

以上就是對this的理解,如有錯誤請狠拍磚。

相關文章