想要理解this,先記住以下兩點:
1:this永遠指向一個對象;
2:this的指向完全取決於函數調用的位置;
①:如果一個函數中有this,但是它沒有被上一級的對象所調用,那麼this指向的就是window,這裏需要説明的是在js的嚴格版中this指向的不是window,但是我們這裏不探討嚴格版的問題(在嚴格版中的默認的this不再是window,而是undefined。)
function fun(){
console.log(this.s);
}
var obj = {
s:'1',
f:fun
}
var s = '2';
obj.f(); //1
fun(); //2
另外還有兩種種特殊情況:
第一種:當this遇到return
1
function fn()
{
this.user = '二狗子';
return {};
}
var a = new fn;
console.log(a.user); //undefined
2.
function fn()
{
this.user = '二狗子';
return function(){};
}
var a = new fn;
console.log(a.user); //undefined
3.
function fn()
{
this.user = '二狗子';
return 1;
}
var a = new fn;
console.log(a.user); //二狗子
4.
function fn()
{
this.user = '二狗子';
return undefined;
}
var a = new fn;
console.log(a.user); //二狗子
5.
function fn()
{
this.user = '二狗子';
return null;
}
var a = new fn;
console.log(a.user); //二狗子
總結:如果返回值是一個對象,那麼this指向的就是那個返回的對象,如果返回值不是一個對象那麼this還是指向函數的實例。
還有一點就是雖然null也是對象,但是在這裏this還是指向那個函數的實例,因為null比較特殊。
this使用最頻繁的幾種情況做一個總結,最常見的基本就是以下5種:
對象中的方法,事件綁定 ,構造函數 ,定時器,函數對象的call()、apply() 方法;
事件綁定中的this
行內綁定事件:
當事件觸發時,屬性值就會作為JS代碼被執行,當前運行環境下沒有clickFun函數,因此瀏覽器就需要跳出當前運行環境,在整個環境中尋找一個叫clickFun的函數並執行這個函數,所以函數內部的this就指向了全局對象window;如果不是一個函數調用,直接在當前節點對象環境下使用this,那麼顯然this就會指向當前節點對象;
<input type="button" value="按鈕" onclick="clickFun()">
<script>
function clickFun(){
console.log(this) //打印window對象
this // 此函數的運行環境在全局window對象下,因此this指向window;
}
</script>
<input type="button" value="按鈕1" onclick="clickFun">
<input type="button" value="按鈕2" onclick="clickFun"><!--打印input節點-->
<!-- 運行環境在節點對象中,因此this指向本節點對象 -->
動態綁定與事件監聽:
<input type="button" value="按鈕" id="btn">
<script>
var btn = document.getElementById('btn');
btn.onclick = function(){
this ; // this指向本節點對象
}
</script>
構造函數中的this
function Pro(){
this.x = '1';
this.y = function(){};
}
var p = new Pro();
new 一個構造函數並執行函數內部代碼的過程就是這個五個步驟,當 JS 引擎指向到第3步的時候,會強制的將this指向新創建出來的這個對象;
window定時器中的this
var obj = {
fun:function(){
this ;
}
}
setInterval(obj.fun,1000); // this指向window對象
setInterval('obj.fun()',1000); // this指向obj對象
setInterval() 是window對象下內置的一個方法;
在上面的代碼中,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 對象;
函數對象的call()、apply() 方法
函數作為對象提供了call(),apply() 方法,他們也可以用來調用函數,這兩個方法都接受一個對象作為參數,用來指定本次調用時函數中this的指向
call()方法
var lisi = {names:'lisi'};
var zs = {names:'zhangsan'};
function f(age){
console.log(this.names);
console.log(age);
}
f(23);//undefined
//將f函數中的this指向固定到對象zs上;
f.call(zs,32);//zhangsan
apply()方法
var lisi = {name:'lisi'};
var zs = {name:'zhangsan'};
function f(age,sex){
console.log(this.name+age+sex);
}
//將f函數中的this指向固定到對象zs上;
f.apply(zs,[23,'nan']);
注意:call和apply的作用一致,區別僅僅在函數實參參數傳遞的方式上;
這個兩個方法的最大作用基本就是用來強制指定函數調用時this的指向;