1.關于防抖/節流
題目要求很明確,要求最終輸出“searchText1”,并且在500ms后輸出“searchText7”,很明顯就是關于同一個函式在短時間內重復呼叫,如何限制其呼叫頻率的功能實作,
1 function throttle(action, threshold) { 2 // TODO: 3 } 4 5 let timer = true; 6 const triggerScroll = throttle((val) => { 7 console.log(val); 8 }, 300); 9 10 triggerScroll("searchText1"); 11 triggerScroll("searchText2"); 12 triggerScroll("searchText3"); 13 triggerScroll("searchText4"); 14 triggerScroll("searchText5"); 15 triggerScroll("searchText6"); 16 17 setTimeout(() => {}, 500); 18 19 // 期望輸出結果: 20 // searchText1 21 // 500ms 后輸出 searchText7
首先,拿到題目后我們先運行一下,運行后報錯,顯示“triggerScroll is not a function”;由于題目中throttle函式沒有回傳值,所以triggerScroll接收到的throttle回傳值為undefined,首先我們要在throttle函式中return一個函式,也就是throttle在呼叫時傳進去的第一個引數,
1 function throttle(action, threshold) { 2 return action 3 }
這時再運行,控制臺列印“searchText1-6”;這時我們只需要把防抖的通用模板套進去就可以實作了,我這里用的防抖,其實使用節流函式也是可以實作的,原理相同,我這里就不展示了,完整代碼如下:
1 function throttle(action, threshold) { 2 return action 3 } 4 5 let timer = true; 6 const triggerScroll = throttle((val) => { 7 if (timer) { 8 timer = false; 9 setTimeout(() => { 10 timer = true; 11 console.log(val); 12 }, 300) 13 } else { 14 return false; 15 } 16 }, 300); 17 18 triggerScroll("searchText1"); 19 triggerScroll("searchText2"); 20 triggerScroll("searchText3"); 21 triggerScroll("searchText4"); 22 triggerScroll("searchText5"); 23 triggerScroll("searchText6"); 24 25 setTimeout(() => { 26 triggerScroll("searchText7"); 27 }, 500);
另附上防抖和節流的通用模板:
//防抖 let timeid = null; function debounce() { if (timeid) { clearTimeout(timeid); } timeid = setTimeout(() => { //這里寫操作 console.log(Math.random()); }, 500); } window.onscroll = debounce;//視窗滾動事件防抖
//節流 let timeid = null; function debounce(func, wait = 0) { if (!timeid) { timeid = setTimeout(() => { console.log(Math.random()); timeid = null; }, 500); } } window.onscroll = debounce;
2.js預編譯以及運行流程
最終輸出結果為“1 1 2 0”,這一題也會涉及到閉包,作用域等知識點,
1 var i = 0; 2 function fn() { 3 i = 1; 4 console.log(i); 5 var i; 6 return function () { 7 console.log(i); 8 i += 1; 9 } 10 } 11 12 var fun = fn();//1 13 fun();//1 14 fun();//2 15 console.log(i);//0
首先我們需要了解js運行流程:首先進行語法決議;先通篇的檢查js語法,若語法有誤,則報錯,其實進行預編譯;即發生在代碼執行之前,為代碼的執行做的準備作業,一般表現于變數提升,即把變數的宣告提前,但是賦值還是在回應位置賦值,再者就是把整個函式宣告提前,最后js運行流程進入最后一步即決議執行,
搞懂js運行流程再區分作用域,即全域作用域和函式作用域,全域作用域顧名思義就是全域宣告的變數或函式等,函式作用域也就是函式內部的作用域,在函式內部中宣告的變數或函式是不會傳到全域作用域的,
搞懂這兩個概念這一題就能夠迎刃而解了,首先全域宣告了一個變數i并賦值為0,在宣告一個fun接受fn執行后的回傳值,所以fn會執行一次,區域變數i在fn函式中重新宣告,變數提升,這時函式fn中使用的i都為函式作用域中宣告的i,并且重新賦值為1,輸出結果1,這里不會影響到全域變數i的值,再觀望整體代碼,全域變數i未被重新賦值,所以最后一行i輸出為0.
再往下走,fu函式的回傳值也是一個函式,所以fun接收到的是一個函式,fun函式被執行兩次,注意到在fn函式中,i被重新宣告過,所以這里的回傳值函式即fun函式的作用域為區域作用域,使用的變數i為區域變數,即再fn函式中宣告的i,所以輸出1,輸出之后i自增1,即 i = i+1,區域作用域i的值在fun函式弟一次執行后變為2,再次執行后,輸出i為2,
3.值型別和參考型別
這一題主要涉及到值型別和參考型別的存盤方式,即堆記憶體和堆疊記憶體,
1 function fn(obj) { 2 obj.name = "name"; 3 obj = new Object(); 4 obj.name = "newName"; 5 } 6 var xt = new Object(); 7 fn(xt); 8 console.log(xt.name);//name
首先題目中宣告了一個函式fn和一個物件xt,呼叫fn函式,并把xt傳入函式,這是第二行的obj和xt都為參考型別,新增了obj的屬性name值也為name,由于此時obj和xt指向的同一片記憶體空間,所以xt也會新增name屬性,并設定值為name,故最后一個輸出name,
在第三行中可以看到obj被重新賦值,即重新開辟了一片記憶體空間,這時obj依然為新增name屬性而不是修改name屬性,并將name屬性設定為newName,所以這是obj新增的屬性不會影響到物件xt的屬性,
4.同步和異步
這一題主要是考察異步代碼和同步代碼執行的先后順序以及js任務佇列,
1 for (let index = 0; index < 5; index++) { 2 setTimeout(() => { 3 console.log(index); 4 }, 200); 5 } 6 7 for (let j = 0; j < 5; j++) { 8 setTimeout(() => { 9 console.log(j); 10 }, 200); 11 }
首先可以看到題目中有兩個回圈體,兩個回圈體中分別有兩個延時200ms的延時器,做題之前我們應該先了解到JavaScript對于同步代碼和異步代碼的處理方式,js會先執行同步代碼,遇到異步代碼(例:延時器、計時器、Promise等)會先放置任務佇列,等待觸發條件依次執行,這個概念了解清楚后這題就能夠迎刃而解了,
首先兩個回圈體為同步代碼,會先執行,此時第一個回圈體會將回圈出的五個延時器放置任務佇列,等待200ms后執行,第二個回圈體也是如此,所以輸出為“0 1 2 3 4 0 1 2 3 4”,
5.宏任務和微任務
此題主要是考察對于同步異步,以及宏任務和微任務的理解,
//寫出執行結果 setTimeout(() => { console.log(1); }, 0); new Promise((res) => { console.log(2); for (var index = 0; index < 1000; index++) { index = 9999 && res() } console.log(3); }).then(() => { console.log(4); }) console.log(5);
此題最終輸出結果為“2 3 5 4 1”;
解答此題我們需要先了解到Promise的特性,Promise是異步編程的一種解決方案,是解決恐怖回呼/回呼噩夢的一種方案,其就相當于一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果,
創建promise物件,function就相當于容器,用于存放異步代碼(不僅限于異步,同步也可以),此函式在頁面加載時會正常執行,同步代碼會進入主執行緒執行,異步代碼會進入任務佇列,未來才會得到結果,并且Promise有三種狀態,進行時(pending默認值),已成功(fulfilled/resolved),已失敗(rejected)一旦狀態改變,就不會再變,任何時候都可以得到這個結果,成功后會呼叫.then()方法,then方法接受兩個引數,皆為回呼函式,第一個函式promise狀態變為已成功時觸發的,第二個函式promise狀態變為已失敗時觸發,
了解了Promise后,我們還需要搞清楚宏任務和微任務的概念,在上面我們提到過,js會見異步代碼放置任務佇列,宏任務是由宿主(Node、瀏覽器)發起的,常見的就是計時器和延時器;而微任務是由js引擎發起的,常見的就時Promise;執行順序為微任務先執行,宏任務后執行,
這時我們就可以來解答這個題目了,首先遇到延時器,為宏任務,放入任務佇列,其實遇到promise,先執行promise的同步代碼,輸出2,再進入回圈,第一次進入回圈index被重新賦值為9999,并且將promise的狀態改為已成功,再往下走輸出3;
此時promise狀態為已成功,觸發then方法的第一個函式,但是promise回應為異步回應,并且為微任務,放置任務佇列,排在宏任務之前,再往下走就輸出5,
此時同步代碼執行完畢,開始執行異步代碼,先執行微任務,輸出4,在執行延時器代碼,輸出5,
好啦,以上就是小譚今天分享的內容啦,也歡迎各位一起來討論技術呀!文章中有不足的地方小譚也歡迎各位指正探討,不勝感激!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/315996.html
標籤:其他
上一篇:簡述JS正則RegExp物件
下一篇:深入理解margin屬性
