關于setTimeout的this的思考

在《高程3》中關于setTimeout的this的描述是:超時調用的代碼都是在全局作用域中執(zhí)行的拴签,因此函數(shù)中this的值在非嚴格模式下指向window對象神汹,在嚴格模式下是undefined岔乔,那為什么是這樣呢既绩,我們可以簡單的理解為setTimeout為window對象下的一個方法屋群,本文僅討論非嚴格模式下的情況褂删。依據(jù)高程三的結論开伏,如果真正理解了膀跌,我們可以搞定遇到的百分之90的問題,如:

setTimeout(console.log(this),0)//window
let obj = {
    print : function () {
        setTimeout(function () {
            console.log('setTimeout:'+this);
        },0);
    }
}; 
obj.print() //setTimeout: window
function say() {
            console.log('setTimeout:'+this);
        }let obj = {
    print : function () {
        setTimeout(say,0);
    }
}; 
obj.print() //setTimeout: window

無論是直接引用固灵、通過對象方法調用還是函數(shù)引用都很容易理解捅伤,有時候,我們會遇到兩個this的情況巫玻,如下丛忆,一個是setTimeout調用環(huán)境中的this,一個是延遲執(zhí)行函數(shù)中的this仍秤,這個時候需要注意區(qū)別蘸际,我們可以理解為,setTimeout中的第一個參數(shù)就是一個單純的函數(shù)的引用而已徒扶,它的指向跟我們一般的函數(shù)調用時一樣取決于被調用時所處的環(huán)境粮彤。

let obj = {
      say : function () {
            console.log(this);  //延遲執(zhí)行函數(shù)中的this
        },
    print : function () {
        setTimeout(this.say,0); //setTimeout調用環(huán)境中的this,指向調用者即obj
    }
}; 
obj.print() //setTimeout: window

我們換種寫法讓上面代碼中setTimeout調用環(huán)境中的this指向window姜骡,此時函數(shù)執(zhí)行就不會有什么效果了

let obj = {
      say : function () {
            console.log(this);  //延遲執(zhí)行函數(shù)中的this
        },
      print : function () {
        setTimeout(this.say,0); //setTimeout調用環(huán)境中的this导坟,指向調用者即obj
    }
}; 
let func = obj.print;
func() 

下面再看:

var a = 1;
function func(){
        let a = 2;
        setTimeout(function(){
            console.log(a);
            console.log(this.a);
    },0) 
}
func(); //輸出2 1
var a = 1;
function func(){
       // let a = 2;
        setTimeout(function(){
            console.log(a);
            console.log(this.a);
    },0) 
}
func(); //輸出1 1

可見,在沒有使用this時圈澈,在setTimeout超時調用中變量是跟正常函數(shù)調用時沿著定義時的作用域向上查找的惫周。

那么,當以字符串形式執(zhí)行又是怎么樣呢

var a = 2
function say(a){
  console.log(a)
}
function test(){
  let a = 1;
  setTimeout("say(a)",0)
}
test() //2

var a = 2
function test(){
  let a = 1;
  function say(a){
    console.log(a)
  }
  setTimeout("say(a)",0)
}
test()  //say is not defined

可見康栈,當把say方法移到test內(nèi)部時報錯say is not defined递递,原因是以字符串形式執(zhí)行時javascript內(nèi)部實際上調用了eval(),而eval的執(zhí)行環(huán)境是全局作用域window,全局作用域沒有say方法所以報錯啥么。
將參數(shù)直接以賦值形式傳進去則不會報錯:

var a = 2;
function say(a){
    console.log(a)
}
function test(){
    let a = 1;
    setTimeout("say('hhhh')",0)
  }
test() //hhhh

現(xiàn)在看看結合es6的箭頭函數(shù)時this指向是怎么樣的登舞,大家都知道,由于箭頭函數(shù)不綁定this悬荣, 它會捕獲其所在(即定義的位置)上下文的this值菠秒, 作為自己的this值,在setTimeout中情況亦是如此氯迂。

let obj = {
    name :  "jay",
    print : function () {
        setTimeout(() => {
            console.log(this.name)
    },0);
    }
}; 
obj.print() //jay

如何改變setTimeout的this指向

前面的討論其實已經(jīng)有兩種答案了践叠,即利用中間變量引用外面的this和應用箭頭函數(shù)

方法一
let obj = {
    name :  "jay",
    print : function () {
           let that = this;
        setTimeout(function() {
            console.log(that.name)
    },0);
    }
}; 方法二
let obj = {
    name :  "jay",
    print : function () {
        setTimeout(() => {
            console.log(this.name)
    },0);
    }
}; 

還有一種方法是應用bind方法:

方法三
var name = "window";
 function say(){
  console.log(this.name);
}
let obj = {
  name : "jay",
  print : function(){
    setTimeout(say.bind(this),0)
  }
}
obj.print(); //jay

setTimeout參數(shù)傳遞問題

1.setTimeout(function,milliseconds,param1,param2,...); param1,param2,...是可選項言缤,用于給function提供額外的參數(shù),但是注意禁灼,該特性在IE9及之前的IE不能使用9苄!

function say(name) {
   console.log(name)
 }s
etTimeout(say,0,'jay')

2.字符串形式傳參:

function say(a,b) {
   console.log(a+b)
 } 
//let name = "jay"
setTimeout( "say(3,4)",3000) //三秒后輸出7

注意事項

盡量避免setTimeout第一個參數(shù)為字符串弄捕,setTimeout允許講一個字符串作為第一個參數(shù)哮独,js內(nèi)部將會調用eval()函數(shù)用來動態(tài)執(zhí)行一段字符串腳本,eval()具有許多不可預見的危險性察藐,eval的效率是非常低的,執(zhí)行一段代碼需要先將字符串轉換為可執(zhí)行代碼舟扎,也就是比平常多了一步分飞,并且可能隱式創(chuàng)建全局變量。
setTimeout遞歸調用時注意記得應用clearTimeout清除睹限,以避免無限遞歸造成內(nèi)存泄漏譬猫。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市羡疗,隨后出現(xiàn)的幾起案子染服,更是在濱河造成了極大的恐慌,老刑警劉巖叨恨,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柳刮,死亡現(xiàn)場離奇詭異,居然都是意外死亡痒钝,警方通過查閱死者的電腦和手機秉颗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來送矩,“玉大人蚕甥,你說我怎么就攤上這事《拜” “怎么了菇怀?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長晌块。 經(jīng)常有香客問我爱沟,道長,這世上最難降的妖魔是什么匆背? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任钥顽,我火速辦了婚禮,結果婚禮上靠汁,老公的妹妹穿的比我還像新娘蜂大。我一直安慰自己闽铐,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布奶浦。 她就那樣靜靜地躺著兄墅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪澳叉。 梳的紋絲不亂的頭發(fā)上隙咸,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音成洗,去河邊找鬼五督。 笑死,一個胖子當著我的面吹牛瓶殃,可吹牛的內(nèi)容都是我干的充包。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼遥椿,長吁一口氣:“原來是場噩夢啊……” “哼基矮!你這毒婦竟也來了?” 一聲冷哼從身側響起冠场,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤家浇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后碴裙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钢悲,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年舔株,在試婚紗的時候發(fā)現(xiàn)自己被綠了譬巫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡督笆,死狀恐怖芦昔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情娃肿,我是刑警寧澤咕缎,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站料扰,受9級特大地震影響凭豪,放射性物質發(fā)生泄漏。R本人自食惡果不足惜晒杈,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一嫂伞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦帖努、人聲如沸撰豺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽污桦。三九已至,卻和暖如春匙监,著一層夾襖步出監(jiān)牢的瞬間凡橱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工亭姥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留稼钩,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓达罗,卻偏偏與公主長得像坝撑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子氮块,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容