爲什麼要用this
在一段代碼中,在不同的上下文對象中,會重複性使用部分函數,這樣就需要給相應函數顯示傳入一個上下文對象
隨着使用模式越來越複雜,顯式上下文會讓代碼越來越複雜混亂,而this提供了一個更加優雅的方式來隱式“傳遞”一個對象應用。
原理
- this對象是在運行時基於函數的執行環境綁定的:在全局函數中,this等於window,而當普通函數被當作某個對象的方法調用時,this等於那個對象。注意:匿名函數的執行環境具有全局性,因此其this對象通常指向window
- this既不指向函數自身也不指向函數的詞法作用域
- this綁定和函數聲明的位置沒有任何關係,只取決於函數的調用方式
- 當一個函數被調用時,會創建一個執行上下文,其中包含了調用棧,調用方式和傳入參數等信息。this是其中的一個屬性
定義解釋
- 調用位置:函數被調用的位置而非聲明的位置,其決定了this的綁定
- 調用棧:爲了達到當前執行位置所調用的所有函數
this綁定規則
- 默認綁定:在非嚴格模式下,獨立函數調用,即該函數是直接使用的,不帶有任何修飾的函數引用進行調用的,因此this指向全局對象;在嚴格模式下,不能將全局對象用於默認綁定,因此this綁定在undefined上。
- 隱式綁定:在一個對象內部包含一個指向函數的屬性,並通過這個屬性間接引用函數,從而把this間接(隱性)綁定到這個對象上。
注意:對象屬性只有上一層或者最後一層在調用位置中起作用,如:
function foo() {
console.log(this.a);
}
var obj2 = {
a: 42,
foo : foo
};
var obj1 = {
a: 2,
obj2 : obj2
};
obj1.obj2.foo(); //42
隱性丟失
回調函數丟失this綁定是非常常見的,比如參數傳遞或函數傳入語言內置的函數而不是傳入自己聲明的函數,由於被隱性賦值,所以導致了this的丟失。
-
顯式綁定:在某個對象上強制調用函數時,this被綁定到指定的對象。
如:call(), apply()中,你傳入了一個原始值來當作this的綁定對象,這個原始值會被轉換成它的對象形式。-
硬綁定
在一個函數內部手動調用了call(), apply()方法,因此強制把函數的this綁定到了將傳入的對象,之後無論怎樣調用該函數,this總是綁定到該對象。
注:bind()會把指定的參數設置爲this的上下文並調用原始函數。 -
第三方庫中函數和JS語言和宿主環境中內置新函數,都提供了一個可選參數,通常被稱爲上下文,確保回調函數使用指定的this
-
-
new綁定: 包括內置對象函數在內的所有函數都可以使用new來調用,這種函數調用被稱爲構造函數的調用。它會創造一個全新的對象,新對象會綁定到函數調用的this,若函數沒有返回其他對象,那麼new表達式中的函數調用會自動返回這個新對象。
綁定規則:
-
函數是否在new中調用,如果是的話this綁定的是新創建的對象
-
函數是否通過call,apply(顯式綁定)或者硬綁定,如果是的話,this綁定的是指定對象
-
函數是否在某個上下文中調用(隱式綁定),如果是的話,this綁定的是那個上下文對象
-
如果都不是的話使用默認綁定,在嚴格模式下綁定的爲undefined,非嚴格模式下爲全局對象
-
若把null或undefined作爲this綁定對象傳入call,apply或bind,這些值調用的時候會被忽略,使用默認綁定規則
-
函數在發生了間接引用的時候,使用默認綁定規則,如賦值的情況
注意:對於默認綁定來說,決定this的綁定對象並不是調用位置是否處於嚴格模式,而是函數體是否處於嚴格模式。 -
**軟綁定:**給默認綁定指定了一個全局對象或者undefined以外的值,可以實現和硬綁定一樣的效果同時也保留隱式綁定或者顯式綁定修改this的能力。
this詞法
箭頭函數斌不是this的四種標準規則,而是根據外層(函數或者全局)作用域來決定this,箭頭函數的this同時也無法修改。