詳解JS中定時器setInterval和setTImeout的this指向問題
前言
Js是一個單線程語言,可以通過setTimeout()和setInterval()來設(shè)置代碼在指定時刻運行,前者是在指定時間后執(zhí)行,后者是指每隔一段時間執(zhí)行。兩者的使用方法類似。
最近在練習(xí)寫一個小例子的時候用到了定時器,發(fā)現(xiàn)在setInterval和setTimeout中傳入函數(shù)時,函數(shù)中的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中函數(shù)內(nèi)的this是指向了window對象,這是由于setTimeout()
調(diào)用的代碼運行在與所在函數(shù)完全分離的執(zhí)行環(huán)境上. 這會導(dǎo)致這些代碼中包含的 this 關(guān)鍵字會指向 window (或全局)對象。詳細可參考MDN setTimeout
但是在setTimeout中傳入的不是函數(shù)時,this則指向當前對象,如下例:
var num = 0; function Obj (){ this.num = 1, this.getNum = function(){ console.log(this.num); }, this.getNumLater = function(){ setTimeout(console.log(this.num), 1000) } } var obj = new Obj; obj.getNum();//1 打印的為obj.num,值為1 obj.getNumLater()//1 打印的為obj.num,值為1
從以上兩個例子可以看出,當在setTimeout中傳入的參數(shù)為函數(shù)時,函數(shù)內(nèi)部的this才會指向window對象。
當在setTimeout中傳入了一個函數(shù),若想要讓this指向正確的值,可以使用以下兩種比較常用的方法來使this指向正確的值:
1.將當前對象的this存為一個變量,定時器內(nèi)的函數(shù)利用閉包來訪問這個變量
如下:
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
這種方法是將當前對象的引用放在一個變量里,定時器內(nèi)部的函數(shù)來訪問到這個變量,自然就可以得到當前的對象。
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綁定到這個函數(shù)上 } } var obj = new Obj; obj.getNum();//1 打印的為obj.num,值為1 obj.getNumLater()//1 打印的為obj.num,值為1
bind()
方法是在Function.prototype
上的一個方法,當被綁定函數(shù)執(zhí)行時,bind方法會創(chuàng)建一個新函數(shù),并將第一個參數(shù)作為新函數(shù)運行時的this。在這個例子中,在調(diào)用setTimeout中的函數(shù)時,bind方法創(chuàng)建了一個新的函數(shù),并將this傳進新的函數(shù),執(zhí)行的結(jié)果也就是正確的了。關(guān)于bind方法可參考 MDN bind
以上兩種方法都是比較常用的,當然如果使用call或apply方法來代替bind方法,得到的結(jié)果也是正確的,但是call方法會在調(diào)用之后立即執(zhí)行,那樣也就沒有了延時的效果,定時器也就沒有用了,所以推薦使用上述兩種方法來將this傳進setTimeout和setInterval中。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
JavaScript遍歷查找數(shù)組中最大值與最小值的方法示例
這篇文章主要介紹了JavaScript遍歷查找數(shù)組中最大值與最小值的方法,結(jié)合實例形式分析了javascript基于數(shù)組遍歷、判斷實現(xiàn)最大值與最小值計算的相關(guān)操作技巧,需要的朋友可以參考下2019-05-05可能被忽略的一些JavaScript數(shù)組方法細節(jié)
這篇文章主要給大家介紹了一些可能被忽略的JavaScript數(shù)組方法細節(jié),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02