欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS面試之手寫節(jié)流防抖詳解

 更新時間:2023年07月31日 11:28:13   作者:前端平水  
作為一個程序員,代碼實現(xiàn)才是能力體現(xiàn),在大部分面試的時候,我們都會被要求手寫代碼實現(xiàn)一個功能,本文總結(jié)了一下經(jīng)常被面試官問到的節(jié)流和防抖功能的實現(xiàn),分享給有需要的小伙伴

前言

作為一個程序員,代碼實現(xiàn)才是能力體現(xiàn),在大部分面試的時候,我們都會被要求手寫代碼實現(xiàn)一個功能,這需要有良好的代碼習(xí)慣和思路,有時候我們也可以多去看看和理解一些經(jīng)常用到的api源代碼,這是有幫助的。這里我總結(jié)了一下經(jīng)常被面試官問到的節(jié)流和防抖功能的實現(xiàn),分享給有需要的小伙伴

防抖

防抖,就是防止頻繁重復(fù)的觸發(fā)某個事件。比如當(dāng)我們點擊一個按鈕觸發(fā)一個事件時,可能會連續(xù)點了幾次,那么會連續(xù)多次觸發(fā)事件函數(shù),這是一種浪費,尤其是對于異步請求數(shù)據(jù),連續(xù)的請求數(shù)據(jù)很大程度會影響性能和用戶體驗。所以,防抖,就是在觸發(fā)一次函數(shù)后規(guī)定時間內(nèi)沒有再次觸發(fā),再執(zhí)行該事件函數(shù),若多次在規(guī)定時間內(nèi)重復(fù)觸發(fā),只執(zhí)行最后一次觸發(fā)

實現(xiàn)思路

首先,我們要知道,防抖函數(shù)是一個工具函數(shù),我們需要將目標(biāo)事件函數(shù)作為參數(shù)傳入防抖函數(shù),防抖函數(shù)內(nèi)要返回一個調(diào)用了目標(biāo)函數(shù)的函數(shù),當(dāng)調(diào)用防抖函數(shù)時,讓防抖函數(shù)調(diào)用目標(biāo)事件函數(shù),來實現(xiàn)防抖功能。其次,假如從一個中級程序員角度出發(fā),應(yīng)該想到當(dāng)我們把自己寫的防抖函數(shù)作為一個api給初級程序員使用時,希望可以主動設(shè)置防抖的時間間隔,所以這個時間間隔也應(yīng)該是防抖函數(shù)的一個參數(shù)。

function debounce(fn,wait){
    return function(){
        fn()
    }
}

在這個防抖函數(shù)內(nèi),我們要調(diào)用這個傳入的目標(biāo)事件函數(shù),除此之外,我們還要根據(jù)參數(shù)設(shè)置防抖等待的時間,觸發(fā)一次函數(shù)后,要等待該時間間隔再執(zhí)行該目標(biāo)事件函數(shù)。所以我們想到使用計時器setTimeout(),調(diào)用目標(biāo)函數(shù),并且設(shè)置等待時間。當(dāng)我們在等待時間內(nèi)再次觸發(fā)防抖函數(shù),就需要清除之前的計時器,重新等待時間,那么就需要給定時器定義變量名,且調(diào)用清除定時器函數(shù)。

*注:定義定時器變量名需要在返回的函數(shù)外部,形成閉包,否則每次觸發(fā)防抖函數(shù)調(diào)用目標(biāo)事件函數(shù)會重新定義一個同名空變量,導(dǎo)致無法清除之前定時器

function debounce(fn,wait){
    let timeout
    return function(){
        clearTimeout(timeout)
        timeout = setTimeout(fn,wait)
    }
}

到這里我們已經(jīng)完成了大體功能,之后需要我們考慮更多使用這個防抖函數(shù)時可能遇到細節(jié)情況:

比如定義目標(biāo)事件函數(shù)時,可能會使用this來指向觸發(fā)這個事件函數(shù)的DOM結(jié)構(gòu),但是讓該目標(biāo)事件函數(shù)在防抖函數(shù)中的定時器中調(diào)用時,會改變該函數(shù)內(nèi)的this指向window,影響到原函數(shù),所以就需要改正調(diào)用該目標(biāo)函數(shù)的this指向。所以可以使用顯示綁定(call、apply、bind)來維護目標(biāo)事件函數(shù)的this指向。在定時器調(diào)用目標(biāo)事件函數(shù)時,將該函數(shù)顯示綁定到防抖函數(shù)的this,因為當(dāng)防抖函數(shù)被觸發(fā)時,它的this也是指向觸發(fā)這個函數(shù)的DOM結(jié)構(gòu)

function debounce(fn,wait){
    let timeout
    return function(){
        clearTimeout(timeout)
        timeout = setTimeout(()=>{ //改成箭頭函數(shù),否則不能直接接.call()
            fn.call(this)
        },wait)
    }
}

還需要考慮到定義的目標(biāo)事件函數(shù)本身也可能需要傳遞參數(shù),比如可能是事件參數(shù)e,也可能有多個參數(shù)。所以我們需要解構(gòu)出目標(biāo)事件函數(shù)可能接收的所有函數(shù)。使用防抖函數(shù)調(diào)用目標(biāo)事件函數(shù)時,只能將需要傳遞的參數(shù)傳遞給防抖函數(shù),再從防抖函數(shù)解構(gòu)出參數(shù),來傳遞給目標(biāo)事件函數(shù)。arguments就是用來代表函數(shù)接受的所有參數(shù),我們就可以用它解構(gòu)防抖函數(shù)接收到的參數(shù)。

*注:arguments是一個類數(shù)組,需要將其解構(gòu)出來再變成數(shù)組,然后作為參數(shù)傳遞給目標(biāo)函數(shù)。并且輔助函數(shù)call()接收參數(shù)的方式是逐個接收,所以我們需要改成apply(),來接受數(shù)組作為參數(shù)

function debounce(fn,wait){
    let timeout
    return function(){
        let args = [...arguments]
        clearTimeout(timeout)
        timeout = setTimeout(()=>{
            fn.apply(this,args)
        },wait)
    }
}

最后,還需要考慮到,定義的目標(biāo)事件函數(shù)可能有返回值,所以我們還需要定義一個變量來接收目標(biāo)時間函數(shù)調(diào)用后的返回值,并返回這個變量

function debounce(fn,wait){
    let timeout,result //同樣定義在返回函數(shù)外,形成閉包
    return function(){
        let args = [...arguments]
        clearTimeout(timeout)
        timeout = setTimeout(()=>{
            result = fn.apply(this,args)
        },wait)
        return result
    }
}

到這里,一個完整的防抖函數(shù)就實現(xiàn)了,我們可以嘗試簡單驗證一下,源代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="btn">0</button>
    <script>
        let count = 0
        let btn = document.getElementById("btn")
        function add(){
            this.innerHTML = ++count
        }
        function debounce(fn,wait){
            var timeout,result
            return function(){
                let args = [...arguments]
                clearTimeout(timeout)
                timeout = setTimeout(()=>{
                    result = fn.apply(this,args)
                },wait)
                return result
            }
        }
        btn.addEventListener('click',debounce(add,1000))
    </script>
</body>
</html>

節(jié)流

節(jié)流,和防抖類似,都是防止一些不必要的操作,區(qū)別就是,防抖是在規(guī)定時間內(nèi)一直重復(fù)觸發(fā)函數(shù),就一直不執(zhí)行,直到在規(guī)定時間內(nèi)沒有再次觸發(fā),才執(zhí)行;而節(jié)流是在規(guī)定時間內(nèi)一直重復(fù)觸發(fā)函數(shù),那么該規(guī)定時間內(nèi)只會執(zhí)行其中一次。比如,當(dāng)點擊觸發(fā)一個目標(biāo)事件函數(shù),可以直接執(zhí)行這個函數(shù),但是當(dāng)我們在規(guī)定時間內(nèi)又多次重復(fù)觸發(fā)該函數(shù),那么就不執(zhí)行之后的觸發(fā),而規(guī)定時間之后又有觸發(fā)該函數(shù),就又執(zhí)行該函數(shù),并且從這個函數(shù)觸發(fā)的時間開始重新計算時間,之后規(guī)定時間內(nèi)的重復(fù)觸發(fā)也不會被執(zhí)行,這就是節(jié)流

實現(xiàn)思路

節(jié)流的實現(xiàn)思路大體一樣,是一個工具函數(shù),需要傳入目標(biāo)事件函數(shù)和規(guī)定時間作為參數(shù),并且返回一個函數(shù)調(diào)用這個目標(biāo)事件函數(shù),但是這里不需要使用定時器setTimeout(),需要定義一個開始時間,當(dāng)點擊觸發(fā)一個函數(shù)時,將此時的時間賦值給開始時間,之后每次觸發(fā)都判斷此時距離開始時間間隔是否超過規(guī)定時間,若超過就執(zhí)行函數(shù),并且將當(dāng)前時間又賦值給開始時間,若未超過,則不執(zhí)行函數(shù)也不重新賦值開始時間

function throttle(fn,wait){
    let preTime = 0  //同樣使用閉包,保留這個變量
    return function(){
        let now = +new Date()  //一元運算符+改為秒數(shù)時間
        if(now - preTime > wait){
            fn()
            preTime = now
        }
    }
}

另外,同樣需要考慮目標(biāo)事件函數(shù)中的this指向,以及目標(biāo)事件函數(shù)本身需要接收的參數(shù),和可能有返回值得情況。值得注意的是,雖然這里沒有使用setTimeout()定時器,但是函數(shù)調(diào)用在返回出來的函數(shù)中,其內(nèi)部this指向也會被改變,受到影響,所以需要用apply()輔助函數(shù)顯示綁定,改正this指向

function throttle(fn,wait){
    let preTime = 0,result
    return function(){
        let args = [...arguments]
        let now = +new Date()
        if(now - preTime > wait){
            result = fn.apply(this,args)
            preTime = now
        }
        return result
    }
}

到這里,也完成了節(jié)流函數(shù)的手寫實現(xiàn),可以測試一下,源代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="btn">0</button>
    <script>
        let count = 0
        let btn = document.getElementById("btn")
        function add(){
            this.innerHTML = ++count
        }
        function throttle(fn,wait){
            let preTime = 0,result
            return function(){
                let args = [...arguments]
                let now = +new Date()
                if(now - preTime > wait){
                    result = fn.apply(this,args)
                    preTime = now
                }
                return result
            }
        }
        btn.addEventListener('click',throttle(add,1000))
    </script>
</body>
</html>

總結(jié)

在面試中,要求手寫實現(xiàn)功能是經(jīng)常遇到的,而防抖和節(jié)流函數(shù)又是經(jīng)常被要求書寫的函數(shù)之一,大家應(yīng)該也會覺不難,當(dāng)然寫出來也是幫助有需要的小伙伴,希望大家有所收獲,面試一舉拿下

到此這篇關(guān)于JS面試之手寫節(jié)流防抖詳解的文章就介紹到這了,更多相關(guān)JS節(jié)流防抖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript JSON使用原理及注意事項

    JavaScript JSON使用原理及注意事項

    這篇文章主要介紹了JavaScript JSON使用原理及注意事項,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • Javascript 5種方法實現(xiàn)過濾刪除前后所有空格

    Javascript 5種方法實現(xiàn)過濾刪除前后所有空格

    這篇文章主要介紹Javascript 5種過濾刪除前后所有空格的方法,比較實用,需要的朋友可以參考下。
    2016-06-06
  • JavaScript擴展運算符的學(xué)習(xí)及應(yīng)用詳情(ES6)

    JavaScript擴展運算符的學(xué)習(xí)及應(yīng)用詳情(ES6)

    這篇文章主要介紹了JavaScript擴展運算符的學(xué)習(xí)及應(yīng)用詳情(ES6),擴展運算符是ES6新增的一種運算符,他可以幫助我們簡化代碼,簡化操作,具體相關(guān)知識感興趣的小伙伴可以查看下面文章的簡單介紹
    2022-08-08
  • JS實現(xiàn)異步上傳壓縮圖片

    JS實現(xiàn)異步上傳壓縮圖片

    這篇文章主要為大家詳細介紹了JS實現(xiàn)異步上傳壓縮圖片,并立即顯示圖片,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 詳解JavaScript中的構(gòu)造器Constructor模式

    詳解JavaScript中的構(gòu)造器Constructor模式

    構(gòu)造器Constructor不能被繼承,因此不能重寫Overriding,但可以被重載Overloading。通過本文給大家分享JavaScript中的構(gòu)造器Constructor模式,對構(gòu)造器constructor相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧
    2016-01-01
  • 個人總結(jié)的一些JavaScript技巧、實用函數(shù)、簡潔方法、編程細節(jié)

    個人總結(jié)的一些JavaScript技巧、實用函數(shù)、簡潔方法、編程細節(jié)

    這篇文章主要介紹了個人總結(jié)的一些JavaScript技巧、實用函數(shù)、簡潔方法、編程細節(jié),本文講解了變量轉(zhuǎn)換、取整同時轉(zhuǎn)換成數(shù)值型、日期轉(zhuǎn)數(shù)值、類數(shù)組對象轉(zhuǎn)數(shù)組、進制之間的轉(zhuǎn)換等方法技巧,需要的朋友可以參考下
    2015-06-06
  • js+css實現(xiàn)select的美化效果

    js+css實現(xiàn)select的美化效果

    這篇文章主要為大家詳細介紹了js+css實現(xiàn)select的美化效果,如何針對select進行美化,感興趣的小伙伴們可以參考一下
    2016-03-03
  • 微信小程序?qū)崿F(xiàn)授權(quán)登錄

    微信小程序?qū)崿F(xiàn)授權(quán)登錄

    這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)授權(quán)登錄,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • div+css布局的圖片連續(xù)滾動js實現(xiàn)代碼

    div+css布局的圖片連續(xù)滾動js實現(xiàn)代碼

    整理一個div+css圖片連續(xù)滾動代碼,原理跟腳本之家之前發(fā)布的文章一樣。
    2010-05-05
  • webpack自動打包和熱更新的實現(xiàn)方法

    webpack自動打包和熱更新的實現(xiàn)方法

    這篇文章主要介紹了webpack自動打包和熱更新的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06

最新評論