徹底掌握this在JavaScript中的指向,吹散籠罩在this周圍的重重迷霧,理解誰決定了this的指向,看完本篇你能在代碼運行以前就能夠判斷出this的指向。編程
咱們都曾以不一樣的方式在函數中看見過this,但仍然不能準確的指出this在JavaScript中指向誰,本篇將讓你徹底掌握this。瀏覽器
(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中的區別,能夠看這篇文章:
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的指向。