JavaScript 中this在不一樣調用模式中的差別

調用一個函數會暫停當前函數的執行,傳遞控制權和參數給新函數。除了聲明時定義的形式參數,每一個函數還接受兩個附加參數: this 和 arguments。參數 this 的值取決於調用的模式。在JavaScript中一共有4中調用模式: 方法調用模式、函數調用模式、構造器調用模式和 apply 調用模式。數組

方法調用模式(隱式綁定)

當一個函數被保存爲對象的一個屬性時,咱們稱它爲一個方法。當一個方法被調用時,this 被綁定到該對象。若是調用表達式包含一個提取屬性的動做(即包含一個 .點表達式或[subscript]下標表達式),那麼它就是被當作一個方法來調用。app

// 建立 myObject 對象,有一個 value 屬性和一個 increment 方法
// increment 方法接受一個可選的參數。若是參數不是數字,那麼默認使用數字1

var myObject = {
    value: 0,
    increment: function (inc){
        this.value += typeof inc === 'number' ? inc : 1;
    }
};

myObject.increment();
document.writeln(myObject.value);   // 1

myObject.increment(2);
document.writeln(myObject.value);   // 3

方法可使用 this 訪問本身所屬的對象,因此它能從對象中取值貨對對象進行修改。 this 到對象的綁定發生在調用的時候。函數

函數調用模式(默認綁定)

當一個函數並不是一個對象的屬性時,它就是被當作一個函數來調用的。this

var sum = add(3,4);   // sum 的值爲7

以此模式調用函數時,this 被綁定到全局對象。這是語言設計上的一個錯誤。若正確,那麼當內部函數被調用時,this 應該仍然綁定到外部函數的 this 變量。這樣設計的後果就是方法不能利用內部函數來幫助它工做,由於內部函數的 this 被綁定了錯誤的值,不能共享該方法對對象的訪問權。prototype

解決方案: 若是該方法定義一個便令並給它賦值爲 this,那麼內部函數就能夠經過那個變量訪問到 this。按照約定,把那個變量命名爲 that:設計

// 給 myObject 增長一個 double 方法

myObject.double = function () {
    var that = this;   // 解決方法
    
    var helper = function () {
        that.value = add(that.value, that.value);
    };
    
    helper();   // 以函數的形式調用helper
};

// 以方法的形式調用 double

myObject.double();
document.writeln(myObject.value);   // 6

若是使用嚴格模式(strict mode),那麼全局對象沒法使用默認綁定,this 會綁定到undefinedcode

function foo() {
    "use strict";
    
    console.log(this.a);
}

var a = 2;

foo();   // TypeError: this is undefined

這裏有一個微妙可是很是中亞偶的細節,雖然 this 的綁定規則徹底取決於調用位置,可是只有 foo() 運行在非 strict mode 下時,默認綁定才能綁定到全局對象;嚴格模式下與 foo() 的調用位置無關:對象

function foo() {
    console.log(this.a);
}

var a = 2;

(function(){
    "use strict";
    
    foo();   // 2
})();

構造器調用模式

若是在一個函數前面帶上 new 來調用,那麼背地裏將會建立一個鏈接到該函數的 prototype 成員的新對象,同時 this 會被綁定到那個新對象上。繼承

首先,咱們來了解一下構造函數。在傳統的面向類的語言中,「構造函數」是類中的一些特殊方法,使用 new 初始化類時會調用類中的構造函數。一般的形式爲:ip

something = new MyClass(..);

JavaScript也有一個 new 操做符,使用方法看起來和那些面向類的語言同樣,但 JavaScript 中的 new 機制實際上和麪向類語言徹底不一樣。
在 JavaScript 中,構造函數只是一些使用 new 操做符時被調用的函數。它們不屬於某個類,也不會實例化一個類。實際上,它們甚至都不能說是一種特殊的函數類型,它們只是被 new 操做符調用的普通函數而已。包括內置對象函數在內的全部函數均可以用 new 來調用,這種函數調用被稱爲構造函數調用。實際上並不存在所謂的構造函數,只有對於函數的構造調用。
使用 new 來調用函數,會自動執行如下操做:

  1. 建立(或者說構造)一個全新的對象。

  2. 這個新對象會被執行[[原型]]鏈接

  3. 這個新對象會綁定到函數調用的 this

  4. 若是函數沒有返回其餘對象,那麼 new 表達式中的函數會自動返回這個新對象

// 建立一個名爲 Quo 構造器函數。它構造一個帶有 status 屬性的對象

var Quo = function (string) {
    this.status = string;
};

// 給 Quo 的全部實例提供一個名爲 get_status 的公共方法

Quo.prototype.get_status = function () {
    return this.status;
};

// 構造一個 Quo 實例

var myQuo = new Quo("confused");
document.writeln(myQuo.get_status());   // confused

Apply 調用模式

apply 方法讓咱們構建一個參數數組傳遞給調用函數,也容許咱們選擇 this 的值。apply 方法接收兩個參數,第一個是要綁定給 this 的值,第二個就是一個參數數組。

// 構造一個包含兩個數字的數組,並將它們相加

var array = [3,4];
var sum = add.apply(null,array);   // 7

// 構造一個包含 status 成員的對象

var statusObject = {
    status: 'A-OK';
};

// statusObject 並無繼承自 Quo.prototype,但咱們能夠在 statusObject 上調用 get_statuse 方法,儘管statusObject 並無一個名爲 get_status 的方法

var status = Quo.prototype.get_status.apply(statusObject);   // A-OK
相關文章
相關標籤/搜索