溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

前端JS面試中經(jīng)常會被問到的問題有哪些

發(fā)布時間:2021-11-05 16:56:12 來源:億速云 閱讀:108 作者:iii 欄目:web開發(fā)

本篇內(nèi)容介紹了“前端JS面試中經(jīng)常會被問到的問題有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

問題1、事件的節(jié)流(throttle)與防抖(debounce)

有些瀏覽器事件可以在短時間內(nèi)快速觸發(fā)多次,比如調(diào)整窗口大小或向下滾動頁面。例如,監(jiān)聽頁面窗口滾動事件,并且用戶持續(xù)快速地向下滾動頁面,那么滾動事件可能在  3 秒內(nèi)觸發(fā)數(shù)千次,這可能會導致一些嚴重的性能問題。那我們應該如何去避免這樣的問題,下面有兩種方法:

1、節(jié)流(throttle)

節(jié)流的主要思想在于:在某段時間內(nèi),不管你觸發(fā)了多少次回調(diào),都只認第一次,并在計時結束時給予響應。

代碼示例:

// fn是我們需要包裝的事件回調(diào), interval是時間間隔的閾值 function throttle(fn, interval) {   // last為上一次觸發(fā)回調(diào)的時間   let last = 0      // 將throttle處理結果當作函數(shù)返回   return function () {       // 保留調(diào)用時的this上下文       let context = this       // 保留調(diào)用時傳入的參數(shù)       let args = arguments       // 記錄本次觸發(fā)回調(diào)的時間       let now = +new Date()              // 判斷上次觸發(fā)的時間和本次觸發(fā)的時間差是否小于時間間隔的閾值       if (now - last >= interval) {       // 如果時間間隔大于我們設定的時間間隔閾值,則執(zhí)行回調(diào)           last = now;           fn.apply(context, args);       }     } }  // 用throttle來包裝scroll的回調(diào) const better_scroll = throttle(() => console.log('觸發(fā)了滾動事件'), 1000)  document.addEventListener('scroll', better_scroll)

2、防抖(Debounce)

防抖的主要思想在于:我會等你到底。在某段時間內(nèi),不管你觸發(fā)了多少次回調(diào),我都只認最后一次。

代碼示例:

// fn是我們需要包裝的事件回調(diào), delay是每次推遲執(zhí)行的等待時間 function debounce(fn, delay) {   // 定時器   let timer = null      // 將debounce處理結果當作函數(shù)返回   return function () {     // 保留調(diào)用時的this上下文     let context = this     // 保留調(diào)用時傳入的參數(shù)     let args = arguments      // 每次事件被觸發(fā)時,都去清除之前的舊定時器     if(timer) {         clearTimeout(timer)     }     // 設立新定時器     timer = setTimeout(function () {       fn.apply(context, args)     }, delay)   } }  // 用debounce來包裝scroll的回調(diào) const better_scroll = debounce(() => console.log('觸發(fā)了滾動事件'), 1000)  document.addEventListener('scroll', better_scroll)

3、節(jié)流和防抖的實際應用

在我們的應用中,單一的應用節(jié)流或者防抖都不是一個好主意。

場景:如果用戶的操作十分頻繁——他每次都不等 debounce 設置的 delay 時間結束就進行下一次操作,于是每次 debounce  都為該用戶重新生成定時器,回調(diào)函數(shù)被延遲了不計其數(shù)次。頻繁的延遲會導致用戶遲遲得不到響應,用戶同樣會產(chǎn)生“這個頁面卡死了”的觀感。

為了避免弄巧成拙,我們需要借力 throttle 的思想,打造一個“有底線”的 debounce——等你可以,但我有我的原則:delay  時間內(nèi),我可以為你重新生成定時器;但只要delay的時間到了,我必須要給用戶一個響應。這個節(jié)流與防抖結合的思路。

代碼示例:

// fn是我們需要包裝的事件回調(diào), delay是時間間隔的閾值 function throttle(fn, delay) {   // last為上一次觸發(fā)回調(diào)的時間, timer是定時器   let last = 0, timer = null   // 將throttle處理結果當作函數(shù)返回      return function () {      // 保留調(diào)用時的this上下文     let context = this     // 保留調(diào)用時傳入的參數(shù)     let args = arguments     // 記錄本次觸發(fā)回調(diào)的時間     let now = +new Date()          // 判斷上次觸發(fā)的時間和本次觸發(fā)的時間差是否小于時間間隔的閾值     if (now - last < delay) {     // 如果時間間隔小于我們設定的時間間隔閾值,則為本次觸發(fā)操作設立一個新的定時器        clearTimeout(timer)        timer = setTimeout(function () {           last = now           fn.apply(context, args)         }, delay)     } else {         // 如果時間間隔超出了我們設定的時間間隔閾值,那就不等了,無論如何要反饋給用戶一次響應         last = now         fn.apply(context, args)     }   } }  // 用新的throttle包裝scroll的回調(diào) const better_scroll = throttle(() => console.log('觸發(fā)了滾動事件'), 1000)  document.addEventListener('scroll', better_scroll)

問題2、事件委托代理

傳統(tǒng)的事件綁定方式:

<ul id="todo-app">   <li class="item">Walk the dog</li>   <li class="item">Pay bills</li>   <li class="item">Make dinner</li>   <li class="item">Code for one hour</li> </ul>  document.addEventListener('DOMContentLoaded', function() {   let app = document.getElementById('todo-app');   let itimes = app.getElementsByClassName('item');    for (let item of items) {     item.addEventListener('click', function(){       alert('you clicked on item: ' + item.innerHTML);     })   } })

雖然這在技術上是沒什么問題的,但問題是要將事件分別綁定到每個項。這對于目前 4 個元素來說,沒什么大問題,但是如果在待辦事項列表中添加了 10,000  項(他們可能有很多事情要做)怎么辦?然后,函數(shù)將創(chuàng)建 10,000 個獨立的事件偵聽器,并將每個事件監(jiān)聽器綁定到 DOM  ,這樣代碼執(zhí)行的效率非常低下。如何高效的進行事件綁定:

基于事件委托的代碼示例:

document.addEventListener('DOMContentLoaded', function() {   let app = document.getElementById('todo-app');    app.addEventListener('click', function(e) {     if (e.target && e.target.nodeName === 'LI') {       let item = e.target;       alert('you clicked on item: ' + item.innerHTML)     }   }) })

問題3、閉包的使用

閉包常常出現(xiàn)在面試中,以便面試官衡量你對 JS 的熟悉程度,以及你是否知道何時使用閉包。

閉包基本上是內(nèi)部函數(shù)可以訪問其范圍之外的變量。 閉包可用于實現(xiàn)隱藏變量和創(chuàng)建函數(shù)工廠。

不正確的閉包應用:

const arr = [10, 12, 15, 21]; for (var i = 0; i < arr.length; i++) {   setTimeout(function() {     console.log('The index of this number is: ' + i);   }, 3000); }

如果運行上面代碼,3 秒延遲后你會看到,實際上每次打印輸出是 4,而不是期望的 0,1,2,3 。

原因是因為 setTimeout 函數(shù)創(chuàng)建了一個可以訪問其外部作用域的函數(shù)(閉包),該作用域是包含索引 i 的循環(huán)。 經(jīng)過 3 秒后,執(zhí)行該函數(shù)并打印出  i 的值,該值在循環(huán)結束時為 4,因為它循環(huán)經(jīng)過0,1,2,3,4并且循環(huán)最終停止在 4。

正確的閉包使用:

//方法一: const arr = [10, 12, 15, 21];  for (var i = 0; i < arr.length; i++) {   setTimeout(function(i_local){     return function () {       console.log('The index of this number is: ' + i_local);     }   }(i), 3000) }  //方法二: const arr = [10, 12, 15, 21]; for (let i = 0; i < arr.length; i++) {   setTimeout(function() {     console.log('The index of this number is: ' + i);   }, 3000); }

“前端JS面試中經(jīng)常會被問到的問題有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網(wǎng)站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

js
AI