JavaScript--this的綁定規則

JavaScript中有四條調用規則,我們可以根據這四條調用規則來判斷當前this的指向。

第一條:默認綁定。

function foo(){
    console.log(this.a);
}
var a = 2;
foo();   // 2
代碼很簡單,那要怎麼給默認綁定一個定義呢?答案就是:不帶任何修飾的函數引用進行調用
這個時候this指向window.(嚴格模式下指向undefined)

第二條:隱式綁定

隱式綁定,需要在一個對象內部包含一個指向函數的屬性,並通過這個屬性間接引用函數,從而把this間接綁定到這個對象上。

function foo(){
    console.log(this.a);
}
var obj = {
    a:2,
    foo:foo
}
obj.foo();   // 2
這裏在調用的時候增加了一個上下文對象,隱式綁定會把函數調用中的this綁定到這個上下文對象。如果存在多層,按照最近的一層合賬。a.b.c.foo();   則實際指向的是c.

在這裏呢,有一種特殊的情況,函數的賦值操作。

function foo(){
    console.log(this.a);
}
function lee(func){
    func();
}
var obj = {
    a:2,
    foo:foo
}
var a = 1;
doFoo(obj.foo);    //1
看似是隱式綁定,但是函數在傳遞參數的時候就執行了賦值操作,這個時候再次調用的綁定規則應該爲默認綁定,所以指向window.

第三條:顯式綁定

這裏呢,關於call和apply以及bind的知識,之前有說過,不清楚的可以先了解一下。

這些函數都可以直接指定this的指向,所以是顯式綁定。call和apply 仍然可以通過調用時傳遞的參數去修改當前this的綁定,現在想象一個場景:在一個函數內部要調用一個函數,需要將這個函數綁定在一個obj對象上,但是會有其他因素影響函數綁定到obj對象上,這樣一來就會產生丟失綁定的問題。這個時候可以使用硬綁定:

function foo(){
    console.log(this.a);
}
var obj = {
    a:2,
}

var bar = function(){
    foo.call(obj);
}
bar();   //2
setTimeout(bar,100);   //2
bar.call(window);   //2
這樣一來,就無法修改函數的綁定對象了。

ES5提供了內置方法,Function.prototype.bind方法,每個function都自帶bind方法,

var bar = foo.bind(obj)
如此就可以使用了。

第四條:new綁定

也就是通過new去實例化一個對象。、

function foo(a){
    this.a = a;
}
var bar = new foo(2);
console.log(bar.a);   //2
一言以蔽之:構造一個新對象,並把它綁定到foo()調用中的this上

多說一句:這裏foo()是一個普通的函數,通過new關鍵字調用就是對函數的構造調用。由此可得出JS中實際上並不存在所謂的構造函數,只有對函數的構造調用。

優先級:

說了四種方式,既然存在那難免就會有個比較,到底誰更優先呢?

function foo(value){
    this.a = value;
}

var obj1 = {
    foo:foo
}

var obj2 = {}

obj1.foo(2);
console.log(obj1.a);   //2

obj1.foo.call(obj2,3);
console.log(obj2.a);   //3  顯式 > 隱式
--------------------------------------------

var oo1 = {};
var bar = foo.bind(oo1);
bar(2);    //001.a = 2

var oo2 = new bar(3);

//  oo1.a = 2,oo2.a = 3;   => new > 顯式
之前我們看過的硬綁定的實現方式,按道理來說應該是無法修改纔對的,而實際使用的時候bind()有自己的實現機制,所以new調用仍然會修改當前指向對象。

這裏是傳統的四種綁定方式,有沒有例外呢,有。感興趣的可以看下我總結的箭頭函數對this的影響








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