亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

setTimeout閉包疑問

setTimeout閉包疑問

眼眸繁星 2019-04-13 08:36:42
代碼如下:jsvardiv=$('#appendHere');$('#clickMe').on('click',function(){varthat=this;div.append(checkForWindow(this));setTimeout(function(){div.append(checkForWindow(this));div.append('thatisthe'+that.tagName+'');},300);});functioncheckForWindow(elm){if(elminstanceofWindow){return'thisistheWindow';}elseif(elm.tagName){return('thisisthe'+elm.tagName+'');}else{return('thisis'+elm+'');}}輸出結果:(另見:http://jsfiddle.net/dposin/okjr81ev/light/)thisistheBUTTONthisistheWindowthatistheBUTTON問題來了,setTimeout中的checkForWindow(this)為什么沒有形成閉包,而that又形成閉包了呢?這樣寫就能形成閉包?本來我以為是要這樣寫的:jsfor(vari=0;i
查看完整描述

2 回答

?
www說

TA貢獻1775條經驗 獲得超8個贊

其實JS中的所有function均為(lexical)closure,所以直接理解了函數的定義與執行過程自然就理解closure的特點了。
function在定義的時候(就是生成FunctionObject的)會將當前EC的ScopeChain作為自身的[[Scope]]的屬性值,其中that變量位于當前EC的AO中,因此自然也在settimeout延遲執行函數的[[Scope]]屬性中。
然后在settimeout的延遲執行函數執行時會先構建自己的EC,新EC中的ScopeChain=AO+[[Scope]],然后在延遲函數中訪問that時則在ScopeChain解析這個引用,那自然能找到之前設置的值。
而this是關鍵字,跟變量是不同的,因此不會在ScopeChain上解析。在EC中有一個ContextObject的屬性,我們訪問this其實就是訪問EC的ContextObject,這個屬性是根據函數的調用方式來決定的(暫且這樣理解吧,其實底層有一套比較難理解的規范的)
functioncallMeBaby(){console.log(this)}
callMeBaby()//顯示[objectWindow],this指向window
host={callMeBaby:callMeBaby}
host.callMeBaby()//顯示[objectObject],this指向host
上面可以理解為this就是指向函數調用時的所屬對象,如果沒有所屬對象則指向全局對象(window)。下面示例就只能理解底層原理后才能理解透了,先留個坑吧
(1,host.callMeBaby)()//顯示[objectWindow],this指向window
                            
查看完整回答
反對 回復 2019-04-13
?
開滿天機

TA貢獻1786條經驗 獲得超13個贊

說說個人的理解,樓主可能對閉包的理解有些問題,閉包是指返回的函數能夠保留對其父函數中變量的引用
而樓主說的問題,其實是this的指向問題,和閉包沒有什么關系,現在說說我對上面現象的理解:
div.append(checkForWindow(this));這個里面的this是調用觸發當前函數的element,也就是BUTTON;
然后varthat=this;這里將element賦值給that,這里的that就是個普通的變量名,不是關鍵字,沒有任何特殊意義;
接下來到setTimeout語句,其中傳入的為一個匿名函數,這個不是什么閉包就是個函數,然后這個定時器在300ms之后被調用了,里面又調用了div.append(checkForWindow(this));,這個時候,this的指向已經變了,根據this的定義,this是指向調用當前函數的對象,而對于這種匿名函數的調用,這時this指向的就是頂級的window;因此打印出來就是Window;
最后的that,這個和閉包也沒有什么關系,這個根據作用域的知識,可以知道在匿名函數中沒有這個變量,因此去更加高一級去尋找這個變量,也就是指向BUTTON的this;
最后說說樓主的這個函數
for(vari=0;i<10;i++){
setTimeout((function(i){
console.log(i);
})(i),0);
}
這個其中的
(function(i){
console.log(i);
})(i)
這個叫立即執行函數,其中的i會被存儲起來,是一個閉包,因此會打印出0到9的數字,但是這個寫法對于定時器來說也是有問題的,你會發現不論你的時間間隔設置多長,都是瞬間完成,因為這個函數直接執行了,其實賦值給定時器是一個undefined,也就是說,setTimeout其實沒有執行函數,你看到的打印數字是在你定義setTimeout的時候打印出來的
正確的寫法是
for(vari=0;i<10;i++){
setTimeout((function(i){
returnfunction(){
console.log(i);
}
})(i),xxtime);
}
這樣寫會在xxtimems之后連續執行10個定時器
                            
查看完整回答
反對 回復 2019-04-13
  • 2 回答
  • 0 關注
  • 406 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號