this全面解析(二)

上篇文章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綁定兩種方式。

相關文章
相關標籤/搜索