關於setInterval和setTImeout中的this指向問題


問題描述

前些天在練習寫一個小例子的時候用到了定時器,發現在setInterval和setTimeout中傳入函數時,函數中的this會指向window對象,如下例:

var num = 0;
function Obj (){
    this.num = 1,
    this.getNum = function(){
        console.log(this.num);
    },
    this.getNumLater = function(){
        setTimeout(function(){
            console.log(this.num);
        }, 1000)
    }
}
var obj = new Obj; 
obj.getNum();//1  打印的是obj.num,值為1
obj.getNumLater()//0  打印的是window.num,值為0

問題原因

從上述例子中可以看到setTimeout中函數內的this是指向了window對象,這是由於setTimeout()調用的代碼運行在與所在函數完全分離的執行環境上。這會導致這些代碼中包含的 this 關鍵字會指向 window (或全局)對象。詳細可參考MDN setTimeout

解決方法

若想要讓setTimeout中的this指向正確的值,可以使用以下三種比較常用的方法來使this指向正確的值:

1.將當前對象的this存為一個變量,定時器內的函數利用閉包來訪問這個變量,如下:

var num = 0;
function Obj (){
    var that = this;    //將this存為一個變量,此時的this指向obj
    this.num = 1,
    this.getNum = function(){
        console.log(this.num);
    },
    this.getNumLater = function(){
        setTimeout(function(){
            console.log(that.num);    //利用閉包訪問that,that是一個指向obj的指針
        }, 1000)
    }
}
var obj = new Obj; 
obj.getNum();//1  打印的是obj.num,值為1
obj.getNumLater()//1  打印的是obj.num,值為1

 

這種方法是將當前對象的引用放在一個變量里,定時器內部的函數來訪問到這個變量,自然就可以得到當前的對象。

2.利用bind()方法

var num = 0;
function Obj (){
    this.num = 1,
    this.getNum = function(){
        console.log(this.num);
    },
    this.getNumLater = function(){
        setTimeout(function(){
            console.log(this.num);
        }.bind(this), 1000)    //利用bind()將this綁定到這個函數上
    }
}
var obj = new Obj; 
obj.getNum();//1  打印的為obj.num,值為1
obj.getNumLater()//1  打印的為obj.num,值為1

 

bind()方法是在Function.prototype上的一個方法,當被綁定函數執行時,bind方法會創建一個新函數,並將第一個參數作為新函數運行時的this。在這個例子中,在調用setTimeout中的函數時,bind方法創建了一個新的函數,並將this傳進新的函數,執行的結果也就是正確的了。關於bind方法可參考 MDN bind

3. 箭頭函數

 

var num = 0;
function Obj (){
    this.num = 1,
    this.getNum = function(){
        console.log(this.num);
    },
    this.getNumLater = function(){
        setTimeout(() => {
            console.log(this.num);
        }, 1000)    //箭頭函數中的this總是指向外層調用者,也就是Obj
    }
}
var obj = new Obj; 
obj.getNum();//1  打印的是obj.num,值為1
obj.getNumLater()//1  打印的是obj.num,值為1

 


ES6中的箭頭函數完全修復了this的指向,this總是指向詞法作用域,也就是外層調用者obj,因此利用箭頭函數就可以輕松解決這個問題。

以上三種方法都是比較常用的,當然如果使用call或apply方法來代替bind方法,得到的結果也是正確的,但是call方法會在調用之后立即執行,那樣也就沒有了延時的效果,定時器也就沒有用了,所以推薦使用上述方法來將this傳進setTimeout和setInterval中。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM