js中的this總結

關於this的指向問題算的上是js中的一個十分重要的問題了。今天把這個問題總結下,加深下本身對this的理解。
首先,this的指向問題能夠用一句話總結就是:this老是指向調用的對象,也就是說this指向誰與函數聲明的位置沒有關係,只與調用的位置有關。這是判斷this的一個大致原則,而具體的小原則按照優先級的不一樣大體能夠分爲如下幾點:app

一.優先級:new綁定>顯式綁定>隱式綁定>默認綁定

1.new綁定

new方式是優先級最高的一種調用方式,也就是說只要是出現new方式來調用一個函數,this確定會指向new調用函數新建立的對象。函數

function() thisTo(a){
 this.a=a;
}
var data=new thisTo(2); //在這裏進行了new綁定
console.log(data.a);  //2

2.顯式綁定

顯示綁定指的是經過call()和apply()方法對函數進行的調用,對this影響的優先級僅次於new綁定。this

function thisTo(){
   console.log(this.a);
}
var data={
    a:2
}; 
thisTo.call(data));  //2

3.隱式綁定

隱式綁定是指經過對象的屬性進行添加,從而調用this所在函數,該方式的優先級在顯示綁定以後。編碼

function thisTo(){
   console.log(this.a);
}
var data={
    a:2,
    foo:thisTo //經過屬性引用this所在函數 
};
data.foo(); //2

4.默認綁定

默認綁定是指當上面這三條綁定規則都不符合時採用的綁定規則,默認綁定會把this默認綁定到全局對象中,是優先級最低的綁定規則。prototype

function thisTo(){
   console.log(this.a);
}
var a=2; //a是全局對象的一個同名屬性
thisTo(); //2

二.this綁定的特殊狀況

1.隱式丟失

當進行隱式綁定時,若是進行一次引用賦值或者傳參操做,會形成this的丟失,從而最後將this綁定到全局對象中去。code

1.1 引用賦值丟失對象

function thisTo(){
   console.log(this.a);
}
var data={
    a:2,
    foo:thisTo //經過屬性引用this所在函數 
};
var a=3;//全局屬性

var newData=data.foo; //這裏進行了一次引用賦值 
newData(); // 3

原理:由於newData實際上引用的是foo函數自己,跟data對象沒有任何關係,data對象只是一箇中間橋樑。而newData就是一個自己不帶a屬性的對象,天然最後只能把a綁定到全局對象上了。ip

1.2傳參丟失作用域

function thisTo(){
   console.log(this.a);
}
var data={
    a:2,
    foo:thisTo //經過屬性引用this所在函數 
};
var a=3;//全局屬性

setTimeout(data.foo,100);// 3

原理:setTimeout(fn,delay) { fn(); } 實際上fn是一個參數傳遞的引用(fn=data.foo),與引用丟失的原理同樣io

1.3 Function.prototype.bind()
爲了解決隱式丟失的問題,ES5提供了bind方法,bind()會返回一個硬編碼的新函數,它會把參數設置爲this的上下文並調用原始函數。

function thisTo(){
   console.log(this.a);
}
var data={
    a:2
}; 
var a=3;
var bar=thisTo.bind(data);
console.log(bar()); //2

2.間接引用

間接引用是指一個定義對象的方法引用另外一個對象存在的方法,這種狀況下會使得this進行默認綁定。

function thisTo(){
   console.log(this.a);
}
var data={
  a:2,
  foo:thisTo
};
var newData={
  a:3
}
var a=4;
data.foo(); //2
(newData.foo=data.foo)() //4

原理:newData.foo=data.foo的返回值是目標函數的引用,所以調用的位置其實是foo(),根據以前的隱式丟失裏面說的原則,這裏會應用默認綁定。

3.ES6箭頭函數

ES6的箭頭函數在this這塊是一個特殊的改進,箭頭函數使用了詞法做用域取代了傳統的this機制,因此箭頭函數沒法使用上面所說的這些this優先級的原則,注意的是在箭頭函數中,是根據外層父親做用域來決定this的指向問題。

function thisTo(){
   setTimeout(function(){
    console.log(this.a);
},100);
}
var obj={
 a:2
}
var a=3;
thisTo.call(obj); //3

不用箭頭函數,發生隱式丟失,最後的this默認綁定到全局做用域,輸出3。

function thisTo(){
   setTimeout(()=>{
    console.log(this.a);
},100);
}
var obj={
 a:2
}
var a=3;加粗文字
thisTo.call(obj); //2

用了箭頭函數,不會發生隱式丟失,this綁定到外層父做用域thisTO(),thisTo的被調用者是obj對象,因此最後的this到obj對象中,輸出2。

若是不用箭頭函數實現相同的輸出,能夠採用下面這種方式:

function thisTo(){
   var self=this; //在當前做用域中捕獲this 
   setTimeout(function(){
    console.log(self.a); //傳入self代替以前的this
},100);
}
var obj={
 a:2
}
var a=3;
thisTo.call(obj); //2

三.總結:

this的綁定機制,就是要找到這個函數的直接調用位置,而後應用綁定的四條規則,當出現知足多個規則時,按照優先級的高低決定最終的綁定規則。此外注意幾種特殊狀況,特別是ES6中的箭頭函數。

四.參考書籍:

你不知道的JavaScript上卷

相關文章
相關標籤/搜索