在學習javascript中我們往往會被this的指向問題弄的頭昏轉向,今天我們就來學習一下this的指向問題,和改變this指向的方法。
一.this的指向問題
在學習this的指向問題之前我們需要明白兩點:
1:this永遠指向一個對象;
2:this的指向完全取決于函數調用的位置;
針對上面第一點我們能很好了解,因為在javascript中一切都是對象。第二點其實也是好了解,當函數調用的位置不同是,this的指向的對象就不同,是以可以說this的指向可以動态變換的,下面我們先通過一個簡單的例子來看一下this的指向是變換的
<script>
function fun(){
console.log(this.name);
}
var change={
name:'hello',
f:fun
}
var name ='world'
var result=change.f()//hello
fun();//world
</script>
通過上述例子我們可以很清楚的看到this的指向的變化,因為有一個函數在對象change裡面,是以this就是指向的函數外部的對象,是以輸出了hello。
想必看完上述例子後大家對this的動态指向切換有了一定的了解。
那麼接下來,我們對this使用最頻繁的幾種情況做一個總結,最常見的基本就是以下3種:
對象中的方法,事件綁定 ,構造函數 ,定時器
前兩個就不必多說了,我們看一下定時器中的this指向問題,
var obj = {
fun:function(){
this ;
}
}
setInterval(obj.fun,1000); // this指向window對象
setInterval('obj.fun()',1000); // this指向obj對象
setInterval()
是window對象下内置的一個方法,接受兩個參數,第一個參數允許是一個函數或者是一段可執行的 JS 代碼,第二個參數則是執行前面函數或者代碼的時間間隔;
在上面的代碼中,
setInterval(obj.fun,1000)
的第一個參數是
obj
對象的
fun
,因為 JS 中函數可以被當做值來做引用傳遞,實際就是将這個函數的位址當做參數傳遞給了
setInterval
方法,換句話說就是
setInterval
的第一參數接受了一個函數,那麼此時1000毫秒後,函數的運作就已經是在window對象下了,也就是函數的調用者已經變成了window對象,是以其中的this則指向的全局window對象;
而在
setInterval('obj.fun()',1000)
中的第一個參數,實際則是傳入的一段可執行的 JS 代碼;1000毫秒後當 JS 引擎來執行這段代碼時,則是通過
obj
對象來找到
fun
函數并調用執行,那麼函數的運作環境依然在 對象
obj
内,是以函數内部的this也就指向了
obj
對象;
除了這些我們還需要了解三個可以改變this指向的函數,包括箭頭函數,call(),apply()
箭頭函數:官方有解釋,箭頭函數引入的其中一個原因,就是其不綁定this;在箭頭函數中,箭頭函數的
this
被設定為封閉的詞法環境的,換句話說,箭頭函數中的this取決于該函數被建立時的環境。
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
// 接着上面的代碼
// 作為對象的一個方法調用
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true
// 嘗試使用call來設定this
console.log(foo.call(obj) === globalObject); // true
// 嘗試使用bind來設定this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
無論如何,
foo
的
this
被設定為他被建立時的環境(在上面的例子中,就是全局對象)。這同樣适用于在其他函數内建立的箭頭函數:這些箭頭函數的
this
被設定為封閉的詞法環境的。
// 建立一個含有bar方法的obj對象,
// bar傳回一個函數,
// 這個函數傳回this,
// 這個傳回的函數是以箭頭函數建立的,
// 是以它的this被永久綁定到了它外層函數的this。
// bar的值可以在調用中設定,這反過來又設定了傳回函數的值。
var obj = {
bar: function() {
var x = (() => this);
return x;
}
};
// 作為obj對象的一個方法來調用bar,把它的this綁定到obj。
// 将傳回的函數的引用指派給fn。
var fn = obj.bar();
// 直接調用fn而不設定this,
// 通常(即不使用箭頭函數的情況)預設為全局對象
// 若在嚴格模式則為undefined
console.log(fn() === obj); // true
// 但是注意,如果你隻是引用obj的方法,
// 而沒有調用它
var fn2 = obj.bar;
// 那麼調用箭頭函數後,this指向window,因為它從 bar 繼承了this。
console.log(fn2()() == window); // true
call和apply方法:将一個對象作為call或者apply的第一個參數,this将會被綁定到這個參數對象上
var obj = {parent:'男'};
var parent = '28';
function child(obj){
console.log(this.parent);
}
child(); // 28
child.call(obj); //男
child.apply(obj); //男