this指向
this是函數體內的一個關鍵字, 不同函數和不同的環境都會影響this的值
function函數, this默認指向函數調用者
箭頭函數, this指向外層作用域this的值
node環境中, 注意全局不再是window, 而是global對象
注意: 嚴格模式下, this無法指向window, 並且 this變量無法重新賦值
this綁定規則
1. 默認綁定: 看調用者
- 案例1: 按鈕事件中this的值
<button οnclick="btn2()">再點下</button>
function btn2(){ // 標籤上綁定的事件也是在window環境
console.log(this); // 默認由window調用
}
- 案例2: 默認window調用方法
function fnOne(){
console.log(this); // window
}
fnOne(); // 其實是window.fnOne(), 所以調用者是window
- 案例3: 定時器回調函數
setTimeout(function(){ // setTimeout運行在Window的環境下
console.log(this); // 默認指向window
}, 0);
- 案例4: 匿名自調用函數
(function(){ // 匿名自調用函數運行在window環境下
console.log(this); // 代碼默認前面都有個window.調用, 所以this默認指向window
})();
2. 隱式綁定: 看調用者
- 案例1: JS獲取標籤.事件函數
<button id="btn">點我</button>
document.getElementById("btn").onclick = function(){
console.log(this); // onclick事件綁定到按鈕, 所以this指向btn按鈕
}
- 案例2: 對象調用函數
let obj = {
a: "web前端",
b: function(){
console.log(this); // obj對象
}
}
obj.b(); // b函數的調用者是obj
- 案例3: 取出函數, 再調用
let obj2 = {
a: "web前端",
b: function(){
console.log(this); // window
}
}
let fn = obj2.b; // 這裏不是調用函數, 而是取出函數
fn(); // 默認前面有個window在調用.
- 案例4: 返回函數再調用
let obj3 = {
a: "web前端3",
b: function(){
return function(){
console.log(this); // window
}
}
}
let fn2 = obj3.b(); // 調用后里面return出來function(){}賦予給fn2變量
fn2(); // 默認前面有個window
- 案例5: 返回對象, 調用裏面函數
let obj4 = {
a: "web前端",
b: function(){
return {
c: "h5啊",
d: function(){
console.log(this); // 指向當前c, d爲key的此對象
}
}
}
}
obj4.b().d(); // obj4.b() 得到對象, 然後對象.d()調用的, 所以看好調用者是誰
3. 硬綁定: 直接修改this指向
使用call和apply, 會觸發函數, 替換函數內this該指向的值
如果不傳或者傳null, 還是默認該指向誰就指向誰
function Person(){
this.username = "";
this.age = 0;
}
let obj = {};
Person.call(obj); // call/apply效果相同, 調用Person函數, 修改函數裏this指向的值爲obj對象, 並且在obj對象上添加username和age屬性
// obj的值: {username: "", age: 0}
4. new 綁定
默認配合構造函數使用, 使this指向新的對象
function objectFactory(Base, ...arr) {
// Base 是new 後面的類名
let obj = new Object(); //從Object.prototype上克隆一個對象
obj.__proto__ = Base.prototype; // 繼承Base原型裏屬性/方法
Base.call(obj, ...arr); // 繼承Base構造函數裏屬性/方法
return obj; //返回 obj
}
注意
綁定優先級 new > 硬綁定 > 隱式 > 默認