JavaScript this用法總結

kooorong 8年前發布 | 7K 次閱讀 JavaScript開發 JavaScript

在JavaScript中,this關鍵字可以說是最復雜的機制之一。對this的作用機制缺乏比較深入的理解很容易在實際開發中出現問題。

1、this的作用

為什么要在JavaScript中使用this呢?因為this提供了一種簡明的方式來隱式傳遞一個對象引用,可以讓函數接口設計的簡單且容易復用:

function display() {
    console.log(this.name);
}

var obj1 = {name: "obj1"};
var obj2 = {name: "obj2"};

display.call(obj1);  //  "obj1"
display.call(obj2);  //  "obj2"

通過call方法,我們可以在調用display函數時為this傳入不同的對象。如果不使用this關鍵字,那么上面的函數就需要顯示增加一個調用時上下文參數:

function display(context) {
    console.log(context.name);
}

var obj1 = {name: "obj1"};
var obj2 = {name: "obj2"};

display(obj1);  //  "obj1"
display(obj2);  //  "obj2"

實際上這不夠簡潔,當使用模式比較復雜時,顯示的上下文傳遞會讓代碼變得混亂復雜。使用this關鍵字,我們可以在調用時為this傳入不同的對象引用,保證了方法的使用靈活性。

2、this的使用復雜性

this使用機制復雜,在開發容易出問題的根本原因在于:this是在運行時綁定,而不是在編寫時綁定,this實際值取決于函數調用時的上下文。this的綁定和函數聲明的位置沒有關系,只取決于函數的調用方式。在JavaScript中,當函數被調用時,會創建一個活動記錄(執行時上下文),這個記錄包含函數在何處調用、函數的調用方法和傳入參數等信息,this會記錄其中一個屬性。判斷this實際綁定值,關鍵在于分析函數實際調用的位置。

3、this綁定規則

前面說了函數的實際調用位置決定了this的綁定值。在JavaScript中,this有4種綁定規則。

3.1、new綁定

在JavaScript中使用new調用函數會自動執行下面的操作:

(1)創建一個新的對象

(2)對新對象執行原型鏈接

(3)新對象會被綁定到函數的this

(4)如果函數沒有返回其他對象,那么新對象會被返回

new綁定容易理解,下面是一段常見的用new調用函數創建對象的代碼:

function Book(name, author, isbn) {
    this.name = name;
    this.author = author;
    this.isbn = isbn;
}

let book = new Book("Zakas", "ES6", 12345);

console.log(book.name);  //  "Zakas"

3.2、隱式綁定

當對象內部包含一個指向函數的屬性,并且在調用時通過這個屬性間接引用函數(obj.prop()的形式),那么函數內的this會隱式指向這個對象,也即隱式綁定:

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

var obj = {
    a: 2,
    foo: foo
};

obj.foo();  //  2

在調用位置上,函數是通過obj.foo來引用的,可以說函數被調用時obj對象擁有或包含它。此時,this綁定在obj這個上下文對象上。

3.3、顯示綁定

在某些情況下,我們希望函數內的this綁定在某些指定的對象上,這稱為顯示綁定。在JavaScript中可以使用call和apply為函數顯示指定this綁定。call和apply的第一個參數是一個對象,這個對象會被綁定到this上:

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

var obj = {
        a:2
};

foo.call(obj);  //  2

使用bind也可以讓this綁定在指定對象上,bind綁定也是一種顯示綁定,又稱為硬綁定:

function foo(something) {
    this.a = something;
}
var obj1 = {};
var bar = foo.bind(obj1);

bar(2);
console.log(obj1.a);  //  2

3.4、默認綁定

當使用獨立函數調用(func()形式),會發生默認綁定,可以把這條規則看成是無法使用其他規則時的默認規則。看下面的示例代碼:

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

var a = 2;

foo();  //  2

當調用foo時,使用默認綁定規則,this被綁定到全局對象上。在strict模式下,this會綁定到undefined。

4、綁定優先級

上面4種綁定規則獨立使用的話,判斷this的綁定值并不復雜。但實際函數調用時,可能多條綁定規則都可以使用,那么這時就要根據每個規則的綁定優先級來判斷this實際的綁定值。接下來看各種綁定規則的優先級。

4.1、默認綁定優先級最低

默認綁定的優先級最低,這個容易理解。因為當無法使用其他的綁定規則時才會使用默認規則。

4.2、顯示綁定優先級高于隱式綁定

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

var obj1 = {a: 2, foo: foo};
var obj2 = {a: 3, foo: foo};

obj1.foo();  //  2
obj1.foo.call(obj2);  //  3

上面的代碼中,obj1.foo()使用隱式綁定規則,this綁定到obj1對象上。obj1.foo.call()可同時使用隱式綁定和顯示綁定規則,顯示綁定優先級高于隱式綁定,this綁定到obj2對象上。

4.3、new綁定優先級高于隱式綁定

function foo(something) {
    this.a = something;
}

var obj1 = {
    foo: foo
};

var obj2 = {};

obj1.foo(2);
console.log(obj1.a);  //  2

obj1.foo.call(obj2, 3);
console.log(obj2.a);  //  3

var bar = new obj1.foo(4);
console.log(obj1.a);  //  2
console.log(bar.a);  //  4

上面代碼中,new obj1.foo(4)可同時使用new綁定和隱式綁定。由bar.a的值為4可以知道,new綁定優先級高于隱式綁定。

4.4、new綁定優先級高于顯示綁定

function foo(something) {
    this.a = something;
}
var obj1 = {};
var bar = foo.bind(obj1);

bar(2);
console.log(obj1.a);  //  2

var baz = new bar(3);
console.log(obj1.a);  //  2
console.log(baz.a);  //  3

上面代碼中,new bar(3)可同時使用new綁定和bind綁定。baz.a的值為3,說明new綁定優先級高于隱式綁定。

4.5、綜述

現在可以根據this綁定優先級判斷函數在調用位置實際綁定的值。實際可以按照下面的順序判斷:

(1、函數是否在new中調用?如果是的話this綁定新創建的對象。調用例子:var bar = new foo()。

(2、函數是否通過apply、call顯示綁定或者bind硬綁定?如果是,this綁定指定的對象。調用例子:var bar = foo.call(obj)。

(3、函數是否在某個上下文對象中調用(隱式綁定)?如果是,this綁定在上下文對象上。調用例子:var bar = obj.foo()。

(4、如果都不是的話,使用默認綁定。在嚴格模式下,this綁定到undefined,在非嚴格模式下,綁定到全局對象。調用例子:var bar = foo()。

5、箭頭函數中的this

ES6中引入了箭頭函數,箭頭函數使用操作符=>定義。箭頭函數不使用上面4種this綁定規則,而是根據外層作用域來決定this:

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

var obj1 = {a:2};
var obj2 = {a:3};

var bar = foo.call(obj1);
bar.call(obj2);  //  2

foo內部的箭頭函數創建時,foo函數內this綁定到obj1上,bar(箭頭函數)的this也會綁定到obj1上,箭頭函數內的this是不能被修改的。

 

來自:http://www.cnblogs.com/xfshen/p/6011541.html

 

 本文由用戶 kooorong 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!