摘要:而寫(xiě)成還可以滿足你獲得回調(diào)函數(shù)返回值的需求。而構(gòu)建函數(shù)表達(dá)式的方法也不止把聲明括起來(lái)這種,一些其他的操作符也可以,比如賦值號(hào)到目前為止,我們似乎能夠得出結(jié)論函數(shù)聲明后不可直接跟圓括號(hào),而函數(shù)表達(dá)式后面可以。
使用setTimeout替代setInterval
setInterval()這個(gè)間歇調(diào)用函數(shù)是應(yīng)用得比較廣的,尤其在比較古老的瀏覽器中實(shí)現(xiàn)動(dòng)畫(huà)效果時(shí),往往離不開(kāi)它。然而這個(gè)函數(shù)卻有不少坑,由于其實(shí)現(xiàn)是把要執(zhí)行的代碼插入待執(zhí)行隊(duì)列排隊(duì)執(zhí)行,同時(shí)為防止連續(xù)執(zhí)行,這個(gè)隊(duì)列中只能有一個(gè)最早進(jìn)來(lái)的它的代碼實(shí)例。如果隊(duì)列中也有其他任務(wù)在等待,而且執(zhí)行了很長(zhǎng)時(shí)間,首先就很容易導(dǎo)致計(jì)時(shí)不準(zhǔn);再者,還會(huì)打亂其執(zhí)行的時(shí)間線,導(dǎo)致setInterval()遲遲不能再添加新的代碼實(shí)例,最終出現(xiàn)略過(guò)某次執(zhí)行的現(xiàn)象等問(wèn)題,如下圖所示:
如果你要獲取每次間歇執(zhí)行的結(jié)果,那就要避免setInterval()可能略過(guò)某次執(zhí)行缺點(diǎn),可以用setTimeout()改寫(xiě)它:
//原函數(shù) var intervalId = setInterval(function () { if(someCondition) { clearInterval(intervalId); console.log("done"); } }, 1000); //改寫(xiě)后 function fun() { if(someCondition) { console.log("done"); } else { setTimeout(fun, 1000); } } setTimeout(fun, 1000);
雖然setTimeout()的計(jì)時(shí)也未必很準(zhǔn)確,但由于上述代碼是鏈?zhǔn)绞褂玫?,一環(huán)扣一環(huán),從源頭阻止了略過(guò)某次執(zhí)行的情況。同時(shí)使用setTimeout()也更靈活些、定制性更強(qiáng),想執(zhí)行到某個(gè)周期就停下來(lái),只要你不繼續(xù)調(diào)用就可以了,沒(méi)必要專門再加個(gè)clearTimeout()。最后,既然是鏈?zhǔn)綀?zhí)行,那你第一個(gè)調(diào)用可用普通的函數(shù)調(diào)用即可,然后在執(zhí)行時(shí)自然會(huì)調(diào)用setTimeout(),而不用像setInterval()那樣第一個(gè)調(diào)用也必須等待一段時(shí)間,這樣可以滿足一些更細(xì)致的要求。
如何給setTimeout()的回調(diào)函數(shù)傳參?這個(gè)問(wèn)題其實(shí)也代表了一類問(wèn)題,即如何在如setTimeout()、setInterval()、指定DOM事件等限制使用函數(shù)引用而非函數(shù)調(diào)用的場(chǎng)合,仍然能給將來(lái)要調(diào)用的函數(shù)傳遞參數(shù)。
為什么要給函數(shù)傳參?因?yàn)閭鲄⒑头祷刂狄粯?,是函?shù)作為子程序與外界通信的一大手段。但在上面提到那些限制必須使用函數(shù)引用的場(chǎng)景下,如果我們只用函數(shù)的引用而沒(méi)有調(diào)用函數(shù),那就意味著不能給直接給它傳參、也不能接受它的返回值,這就使得子程序間的數(shù)據(jù)通信少了一大功能,此時(shí),你要讓回調(diào)函數(shù)與外界通信貌似也就只有通過(guò)全局變量了。
但深入想一想,這些場(chǎng)景只是規(guī)定要用到函數(shù)引用,并沒(méi)有說(shuō)一定是回調(diào)函數(shù)的引用,那也意味著我們可以偷梁換柱,用別的函數(shù)引用來(lái)“占著”本來(lái)應(yīng)該是回調(diào)函數(shù)引用的位置,而讓回調(diào)函數(shù)進(jìn)行調(diào)用。于是我們就有了解決方法,以setTimeout()為例最簡(jiǎn)單的一種想法如下:
setTimeout(function() { callback(arg); }, timeout);
這里用到一個(gè)匿名函數(shù)作為第一個(gè)參數(shù),匿名函數(shù)提供了它的函數(shù)引用后,回調(diào)函數(shù)就可以在匿名函數(shù)體內(nèi)直接調(diào)用、傳參了。而寫(xiě)成return callback(arg)還可以滿足你獲得回調(diào)函數(shù)返回值的需求。
除了外套匿名函數(shù)這種方法,我們還可以使用功能更加強(qiáng)大的閉包,來(lái)解決這個(gè)傳參問(wèn)題:
setTimeout((function(arg) { return function () { callback(arg); }; })(arg), timeout);
其實(shí)就是在第一種方法的基礎(chǔ)上再外套一個(gè)立即執(zhí)行表達(dá)式,這個(gè)閉包實(shí)際上是包含了傳參操作的,但有了它我們就可以來(lái)解決那些我們通過(guò)構(gòu)造閉包可以解決的的問(wèn)題了。比如獲取某次循環(huán)等更具體的塊級(jí)作用域中的變量值:
for (i in Arr) { setTimeout((function(arg) { return function () { callback(arg); }; })(i), timeout); }函數(shù)聲明和函數(shù)表達(dá)式
在使用立即執(zhí)行表達(dá)式(IIFE)時(shí),我們常采用(function () {})()這種形式,若去掉第一組括號(hào)直接在函數(shù)聲明后面加括號(hào)則會(huì)報(bào)錯(cuò):
function () {}() //Uncaught SyntaxError: Unexpected token (
顯然js的函數(shù)聲明后面是不能直接加括號(hào)讓它立即執(zhí)行的,但我們把函數(shù)聲明括起來(lái),立即執(zhí)行的就不是一個(gè)函數(shù),而是一個(gè)所謂函數(shù)表達(dá)式了。而構(gòu)建函數(shù)表達(dá)式的方法也不止把聲明括起來(lái)這種,一些其他的操作符也可以,比如賦值號(hào):
var A = function () {}();
到目前為止,我們似乎能夠得出結(jié)論:函數(shù)聲明后不可直接跟圓括號(hào),而函數(shù)表達(dá)式后面可以。然而js認(rèn)為什么是函數(shù)聲明、什么是函數(shù)表達(dá)式卻并不是簡(jiǎn)單靠函數(shù)聲明的外在形式來(lái)決定的,比如下面這個(gè)例子:
function A(i){ console.log(i); } A(function () { return 5; }()); //5
上面的代碼里A函數(shù)的參數(shù)直接在函數(shù)聲明后面加上了括號(hào),看起來(lái)是個(gè)非法的IIFE了,而這個(gè)“非法”IIFE作為參數(shù)時(shí)卻能正常地立即執(zhí)行。但再仔細(xì)想想,我們知道傳參的過(guò)程其實(shí)是相當(dāng)于賦值的,所以這種傳參形式其實(shí)和上面提到的通過(guò)賦值號(hào)構(gòu)建函數(shù)表達(dá)式應(yīng)該是一個(gè)道理,立即執(zhí)行的其實(shí)還是是函數(shù)表達(dá)式,而非函數(shù)聲明,不要被表像迷惑了。
而為防止以后讀代碼時(shí)再踩坑,我想出了個(gè)更簡(jiǎn)單的區(qū)分兩者的“方法”:只要function不是放在一個(gè)語(yǔ)句最前面時(shí)就可以連同后面的聲明內(nèi)容當(dāng)作函數(shù)表達(dá)式,就可以加括號(hào)立即執(zhí)行。
當(dāng)然在寫(xiě)代碼用到IIFE時(shí),就沒(méi)必要糾結(jié)這些降低效率了,直接在聲明外括括號(hào)得了,這樣既寫(xiě)起來(lái)方便又看起來(lái)簡(jiǎn)潔明了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/78760.html
摘要:禁止用戶選擇文字在一些應(yīng)用場(chǎng)合,我們不希望用戶能夠選擇文字。在下使用透明效果雖然已經(jīng)停止對(duì)的技術(shù)支持了,然而做前端的還得被它惡心一段時(shí)間,有些兼容性的問(wèn)題是我們?nèi)砸鎸?duì)滴。但是,前端界被虐了這么多年,解決問(wèn)題的方法總是有的。 禁止用戶選擇文字 在一些應(yīng)用場(chǎng)合,我們不希望用戶能夠選擇文字。比如在拖動(dòng)交互中,如果用戶能選擇元素內(nèi)部的文字,也就意味著能拖動(dòng)它們,這樣就會(huì)干擾對(duì)元素的拖動(dòng)、影響...
摘要:禁止用戶選擇文字在一些應(yīng)用場(chǎng)合,我們不希望用戶能夠選擇文字。在下使用透明效果雖然已經(jīng)停止對(duì)的技術(shù)支持了,然而做前端的還得被它惡心一段時(shí)間,有些兼容性的問(wèn)題是我們?nèi)砸鎸?duì)滴。但是,前端界被虐了這么多年,解決問(wèn)題的方法總是有的。 禁止用戶選擇文字 在一些應(yīng)用場(chǎng)合,我們不希望用戶能夠選擇文字。比如在拖動(dòng)交互中,如果用戶能選擇元素內(nèi)部的文字,也就意味著能拖動(dòng)它們,這樣就會(huì)干擾對(duì)元素的拖動(dòng)、影響...
摘要:和屬性數(shù)值對(duì)應(yīng)的是元素的內(nèi)容加所占據(jù)的視覺(jué)面積,有滾動(dòng)條時(shí)還要加上滾動(dòng)條,不含。和仍要分有沒(méi)有滾動(dòng),有滾動(dòng)時(shí)指的是整個(gè)頁(yè)面內(nèi)容的大小沒(méi)滾動(dòng)時(shí)在下指視口的大小和下則是和一樣。與屬性在下都和原來(lái)一樣指整個(gè)元素的可視寬高。 光標(biāo)效果不見(jiàn)了? 在頁(yè)面里,屏幕上光標(biāo)的樣式我們可以用css的cursor屬性進(jìn)行定義。一般來(lái)講,只要光標(biāo)hover到指定的元素上面其樣式就會(huì)按我們指定的進(jìn)行顯示,但是如...
摘要:和屬性數(shù)值對(duì)應(yīng)的是元素的內(nèi)容加所占據(jù)的視覺(jué)面積,有滾動(dòng)條時(shí)還要加上滾動(dòng)條,不含。和仍要分有沒(méi)有滾動(dòng),有滾動(dòng)時(shí)指的是整個(gè)頁(yè)面內(nèi)容的大小沒(méi)滾動(dòng)時(shí)在下指視口的大小和下則是和一樣。與屬性在下都和原來(lái)一樣指整個(gè)元素的可視寬高。 光標(biāo)效果不見(jiàn)了? 在頁(yè)面里,屏幕上光標(biāo)的樣式我們可以用css的cursor屬性進(jìn)行定義。一般來(lái)講,只要光標(biāo)hover到指定的元素上面其樣式就會(huì)按我們指定的進(jìn)行顯示,但是如...
摘要:鍵盤(pán)事件與文本框變化的過(guò)程鍵盤(pán)事件最基本的應(yīng)用場(chǎng)合是控制文本框元素,而我們要討論的,就是幾個(gè)鍵盤(pán)事件發(fā)生的時(shí)機(jī)與文本輸入的過(guò)程的關(guān)系??梢钥吹剑送?,事件并不會(huì)輸出剛按下的字符,說(shuō)明他們?cè)谖谋究蜃兓鞍l(fā)生而在之后發(fā)生。 鍵盤(pán)事件與文本框變化的過(guò)程 鍵盤(pán)事件最基本的應(yīng)用場(chǎng)合是控制文本框元素,而我們要討論的,就是幾個(gè)鍵盤(pán)事件:keydown、keypress、keyup、textInp...
閱讀 2423·2021-11-25 09:43
閱讀 2937·2021-11-24 09:39
閱讀 3004·2019-08-30 11:10
閱讀 1202·2019-08-29 16:34
閱讀 655·2019-08-29 13:25
閱讀 3409·2019-08-29 11:21
閱讀 2919·2019-08-26 11:39
閱讀 2460·2019-08-26 11:34