掌握JS中this指向只需記憶5大原則

徹底掌握this在JavaScript中的指向,吹散籠罩在this周圍的重重迷霧,理解誰決定了this的指向,看完本篇你能在代碼運行以前就能夠判斷出this的指向。編程


咱們都曾以不一樣的方式在函數中看見過this,但仍然不能準確的指出this在JavaScript中指向誰,本篇將讓你徹底掌握this。瀏覽器

5大規則

(1) 若是 new 關鍵詞出如今被調用函數的前面,那麼JavaScript引擎會建立一個新的對象,被調用函數中的this指向的就是這個新建立的函數。markdown

function ConstructorExample() {
    console.log(this);
    this.value = 10;
    console.log(this);
}

new ConstructorExample();

// -> ConstructorExample {}
// -> ConstructorExample { value: 10 }
複製代碼

(2) 若是經過apply、call或者bind的方式觸發函數,那麼函數中的this指向傳入函數的第一個參數。app

function fn() {
    console.log(this);
}

var obj = {
    value: 5
};

var boundFn = fn.bind(obj);

boundFn(); // -> { value: 5 }
fn.call(obj); // -> { value: 5 }
fn.apply(obj); // -> { value: 5 }
複製代碼

(3) 若是一個函數是某個對象的方法,而且對象使用句點符號觸發函數,那麼this指向的就是該函數做爲那個對象的屬性的對象,也就是,this指向句點左邊的對象。函數

var obj = {
    value: 5,
    printThis: function() {
      console.log(this);
    }
};

obj.printThis(); // -> { value: 5, printThis: ƒ }
複製代碼

(4) 若是一個函數做爲FFI被調用,意味着這個函數不符合以上任意一種調用方式,this指向全局對象,在瀏覽器中,便是window。oop

var obj = {
    value: 5,
    printThis: function() {
      console.log(this);
    }
};

obj.printThis(); // -> { value: 5, printThis: ƒ }
複製代碼

注意,第4條規則和第3條很相似,不一樣的是當函數沒有做爲方法被調用時,它將自動隱式編程全局對象的屬性——window。也就是當咱們調用 fn(),能夠理解爲window.fn(),根據第三條規則,fn()函數中的this指向的就是window。this

var obj = {
    value: 5,
    printThis: function() {
      console.log(this);
    }
};

obj.printThis(); // -> { value: 5, printThis: ƒ }
複製代碼

(5) 若是出現上面對條規則的累加狀況,則優先級自1至4遞減,this的指向按照優先級最高的規則判斷。spa

將規則應用於實踐

看一個代碼示例,並使用上面的規則判斷this的指向。code

var obj = {
    value: 'hi',
    printThis: function() {
        console.log(this);
    }
};

var print = obj.printThis;

obj.printThis(); // -> {value: "hi", printThis: ƒ}
print(); // -> Window {stop: ƒ, open: ƒ, alert: ƒ, ...}
複製代碼

obj.prinThis() ,根據第三條規則this指向的就是obj。根據第四條規則print()是FFI,所以this指向window。orm

其實上面的示例也考察你對於 值和引用 在JavaScript中的區別,能夠看這篇文章:

JavaScript中原始值 vs. 引用值

obj對象中printThis這一方法實際上是函數的地址的一個引用,當咱們將obj.printThis賦值給print時,print包含的也是函數的引用,和obj對象一點關係也沒有。obj只是碰巧擁有一個指向這個函數的引用的屬性。

當不適用obj對象觸發函數時,這個函數就是FFI。

應用多項規則

當出現多個上述規則時,將優先級高的「獲勝」,若是規則2和規則3同時存在,則規則2優先:

var obj1 = {
    value: 'hi',
    print: function() {
        console.log(this);
    },
};

var obj2 = { value: 17 };

obj1.print.call(obj2); // -> { value: 17 }
複製代碼

若是規則1和規則3同時被應用,則規則1優先:

var obj1 = {
    value: 'hi',
    print: function() {
        console.log(this);
    },
};

new obj1.print(); // -> print {}
複製代碼

代碼中引用了庫?

有些庫會將this的指向綁定更有用的對象上,好比jQuery庫,在事件處理程序中,this的指向不是全局對象而被綁定到了元素對象上。所以,若是你發現一些不能用上述5項規則解釋的狀況,請閱讀你所使用的庫的官方文檔,找到關於該庫是如何改變this的指向的,一般經過 bind 方法改變this的指向。

相關文章
相關標籤/搜索