上篇文章this全面解析(一)中,咱們說了幾個常見的錯誤認識。javascript
接下來,咱們來看看this究竟是一種什麼樣的機制java
this是運行時綁定,並非在編譯時,上下文取決於函數調用時的各類條件。this綁定和函數的聲明位置沒有任何關係,只取決於函數的調用方式。編程
調用位置是函數在代碼中被調用的位置(不是聲明的位置)。函數
通常來講,尋找調用位置就是找「函數被調用的位置」,但這並不一直是一件簡單事,有些時候,編程模式會隱藏真正的調用位置。oop
不過咱們仍是有辦法的!咱們能夠經過分析調用棧(爲了達到當前執行位置所調用的全部函數),那麼咱們關心的,就是當前執行函數的前一個調用中。post
function baz() {
//當前調用棧:baz
//調用位置是全局做用域
console.log('baz');
bar(); //bar 的調用位置
}
function bar() {
//當前調用棧 baz--> bar
//所以當前調用位置在 baz 中
console.log('bar');
foo(); // foo的調用位置
}
function foo() {
//當前調用棧 baz-> bar ->foo
//當前調用位置在 bar 中
console.log('foo');
}
baz(); //baz調用位置
複製代碼
其實,函數的調用棧也能夠被想象成一個函數調用鏈~ui
獨立函數調用(沒法應用其餘規則時,默認規則就是它了!)this
看這段代碼spa
function foo() {
console.log(this.a);
}
var a = 1;
foo(); //2
複製代碼
首先,咱們須要明白一個知識點:聲明在全局做用域中的變量就是全局對象的一個同名屬性,本質是一個東西,不是複製獲得的code
當咱們調用foo,this.a 被解析成 全局變量a ,調用函數應用了this的默認綁定,this指向全局對象。
不過這裏有一點
雖然this的綁定規則徹底取決於調用位置,可是隻有 foo() 運行在 非嚴格模式下,默認綁定纔會綁定到全局,嚴格模式下,與foo()的調用位置無關。
考慮調用位置,是否有上下文對象。
function foo(){
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
}
obj.foo(); //2
複製代碼
咱們先來看 foo() 的聲明方式,不管是直接在obj中定義仍是先定義,再添加爲引用屬性,這個函數嚴格來講都不屬於obj對象。
可是,調用位置會使用obj上下文來引用函數,因此,你能夠說,調用obj對象時,擁有或者包含它。調用foo()時,this被綁定到obj。this.a 和 obj.a 是同樣的。
對象屬性引用鏈中,只有最後一層影響調用位置
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
}
var obj1 = {
a: 2,
obj2: obj2
}
obj1.obj2.foo(); //42
複製代碼
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函數別名!
var a = "oops, global"; // a 是全局對象的屬性 bar(); // "oops, global"
複製代碼
雖然,bar是obj.foo的一個引用,實際上,引用的是foo函數自己!因此此時 bar() 是一個不帶任何修飾的函數調用。
function foo(){
console.log( this.a );
}
function doFoo(fn) {
fn(); //調用位置
}
var obj = {
a: 2,
foo: foo
}
var a = "global";
doFoo( obj.foo ); //global
複製代碼
參數傳遞其實就是一種隱式賦值,所以咱們傳入函數時也會被隱式賦值,因此結果和上一 個例子同樣。
下篇文章將介紹:顯式綁定和new綁定兩種方式。