轉載
作者:sunshine小小倩
連結:this、apply、call、bind
來源:掘金
this 的指向
在 ES5 中,其實 this 的指向,始終堅持一個原理:this 永遠指向最後調用它的那個對象,來,跟着我朗讀三遍:this 永遠指向最後調用它的那個對象,this 永遠指向最後調用它的那個對象,this 永遠指向最後調用它的那個對象。記住這句話,this 你已經了解一半了。
例1:
var name = "windowsName";
function a() {
var name = "Cherry";
console.log(this.name); // windowsName
console.log("inner:" + this); // inner: Window
}
a();
console.log("outer:" + this) // outer: Window
這個相信大家都知道為什麼
log
的是
windowsName
,因為根據剛剛的那句話“this 永遠指向最後調用它的那個對象”,我們看最後調用
a
的地方
a()
;,前面沒有調用的對象那麼就是全局對象
window
,這就相當于是
window.a()
;注意,這裡我們沒有使用嚴格模式,如果使用嚴格模式的話,全局對象就是
undefined
,那麼就會報錯
Uncaught TypeError: Cannot read property 'name' of undefined
。
例2:
var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this.name); // Cherry
}
}
a.fn();
在這個例子中,函數 fn 是對象 a 調用的,是以列印的值就是 a 中的 name 的值。是不是有一點清晰了呢~
例3:
var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this.name); // Cherry
}
}
window.a.fn();
這裡列印 Cherry 的原因也是因為剛剛那句話“this 永遠指向最後調用它的那個對象”,最後調用它的對象仍然是對象 a。
例4:
var name = "windowsName";
var a = {
// name: "Cherry",
fn : function () {
console.log(this.name); // undefined
}
}
window.a.fn();
這裡為什麼會列印
undefined
呢?這是因為正如剛剛所描述的那樣,調用
fn
的是
a
對象,也就是說
fn
的内部的
this
是對象
a
,而對象
a
中并沒有對
name
進行定義,是以
log
的
this.name
的值是 undefined。
這個例子還是說明了:
this
永遠指向最後調用它的那個對象,因為最後調用
fn
的對象是
a
,是以就算
a
中沒有
name
這個屬性,也不會繼續向上一個對象尋找
this.name
,而是直接輸出
undefined
。
例5:
var name = "windowsName";
var a = {
name : null,
// name: "Cherry",
fn : function () {
console.log(this.name); // windowsName
}
}
var f = a.fn;
f();
這裡你可能會有疑問,為什麼不是
Cherry
,這是因為雖然将 a 對象的 fn 方法指派給變量 f 了,但是沒有調用,再接着跟我念這一句話:“this 永遠指向最後調用它的那個對象”,由于剛剛的 f 并沒有調用,是以 fn() 最後仍然是被
window
調用的。是以 this 指向的也就是
window
。
由以上五個例子我們可以看出,this 的指向并不是在建立的時候就可以确定的,在 es5 中,永遠是this 永遠指向最後調用它的那個對象。
例6:
var name = "windowsName";
function fn() {
var name = 'Cherry';
innerFunction();
function innerFunction() {
console.log(this.name); // windowsName
}
}
fn()
怎麼改變 this 的指向
改變 this 的指向我總結有以下幾種方法:
- 使用 ES6 的箭頭函數
- 在函數内部使用
_this = this
- 使用
、apply
、call
bind
- new 執行個體化一個對象
例7:
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
},);
}
};
a.func2() // this.func1 is not a function
在不使用箭頭函數的情況下,是會報錯的,因為最後調用
setTimeout
的對象是 window,但是在 window 中并沒有 func1 函數。
我們在改變 this 指向這一節将把這個例子作為 demo 進行改造。
箭頭函數
衆所周知,ES6 的箭頭函數是可以避免 ES5 中使用 this 的坑的。箭頭函數的 this 始終指向函數定義時的 this,而非執行時。箭頭函數需要記着這句話:“箭頭函數中沒有 this 綁定,必須通過查找作用域鍊來決定其值,如果箭頭函數被非箭頭函數包含,則 this 綁定的是最近一層非箭頭函數的 this,否則,this 為 undefined”
例8:
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( () => {
this.func1()
},);
}
};
a.func2() // Cherry
在函數内部使用 _this = this
_this = this
例9:
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
var _this = this;
setTimeout( function() {
_this.func1()
},);
}
};
a.func2() // Cherry
這個例子中,在
func2
中,首先設定
var _this = this
;,這裡的
this
是調用
func2
的對象 a,為了防止在
func2
中的
setTimeout
被
window
調用而導緻的在
setTimeout
中的
this
為
window
。我們将
this
(指向變量 a) 指派給一個變量
_this
,這樣,在
func2
中我們使用
_this
就是指向對象 a 了。
使用 apply
、 call
、 bind
apply
call
bind
使用 apply、call、bind 函數也是可以改變 this 的指向的,原理稍後再講,我們先來看一下是怎麼實作的:
使用 apply
例10:
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.apply(a),);
}
};
a.func2() // Cherry
使用 call
例11:
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.call(a),);
}
};
a.func2() // Cherry
使用 bind
例12:
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.bind(a)(),);
}
};
a.func2() // Cherry
後面就不延伸了,因為我自己看到這就快吃不消的,沒有吃透我也不好轉載,有需求的看轉載位址即可!