最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

js防抖具體實現(xiàn)以及詳細原理步驟說明(附實例)

 更新時間:2022年09月01日 11:27:08   作者:指定能行  
節(jié)流和防抖這里兩個詞可能對一些初入JavaScript的同學比較陌生,下面這篇文章主要給大家介紹了關(guān)于js防抖具體實現(xiàn)以及詳細原理步驟的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

ps:本文將從一個案例出發(fā)循序漸進,在其中你不僅能知道防抖是如何實現(xiàn)的,還可以學習到關(guān)于 this 、apply、arguments 等知識的具體應用。

Why?為啥要有防抖?

因為有時候頻繁的事件觸發(fā)是沒有意義的,不僅影響性能還可能造成卡頓。

為了避免這種情況,我們需要用防抖來解決這個問題。

What? 啥是防抖?

防抖debounce:

簡單來說,防抖的效果就是在一定的時間間隔內(nèi),多次觸發(fā)只有一次觸發(fā)產(chǎn)生

How? 防抖咋用???

首先先從一個實例入手:

我們設置一個按鈕用來切換上方文本的顏色,如下:

    <h2 id="demo">hello</h2>
    <button id="btn">點我</button>
 
    <script type="text/javascript">
        var btn = document.getElementById('btn');
 
        btn.addEventListener('click', changeColor, false);
        
        var flag = true
        function changeColor() {
            if (flag) {
                document.getElementById('demo').style.color = 'pink'
            } else {
                document.getElementById('demo').style.color = 'blue'
            }
            flag = !flag
        }

如果你想要讓用戶在1秒內(nèi)不能頻繁切換 ,即1秒內(nèi)只能給文本換一種顏色。

那么你可以利用定時器來實現(xiàn),不過直接寫一個定時器是不夠的,因為你只能實現(xiàn)多次觸發(fā)延時執(zhí)行,而不是限制觸發(fā)。

你可以使用一個變量來判斷你的每次按下按鈕時候是否已經(jīng)觸發(fā)過定時器了,如果觸發(fā)過了就將原來觸發(fā)但還沒到1秒的定時器清除,接著重新來個1秒的定時器;如果沒觸發(fā)過說明你1秒內(nèi)沒按過,新建一個1秒的定時器就行。

這樣就可以保證防抖的效果實現(xiàn)了,請看代碼:

    <h2 id="demo">hello</h2>
    <button id="btn">點我</button>
 
    <script type="text/javascript">
        var btn = document.getElementById('btn');
 
        btn.addEventListener('click', debounce(changeColor), false);
 
        var flag = true
        function changeColor() {
            if (flag) {
                document.getElementById('demo').style.color = 'pink'
            } else {
                document.getElementById('demo').style.color = 'blue'
            }
            flag = !flag
        }
 
        function debounce(fn) {
            let t = null
            return function () {
                //如果定時器存在就清除掉
                if (t) {
                    clearTimeout(t)
                }
                //不然就創(chuàng)建新的定時器
                t = setTimeout(function() {
                    fn()
                }, 1000)
            }
        }
</script>

 看完代碼你可能會有如下疑惑:

1. 怎么這個debounce函數(shù)里面不能直接寫執(zhí)行內(nèi)容嗎?非要return一個函數(shù)?

解:因為你已經(jīng)把changeColor函數(shù)當成參數(shù)傳給debounce函數(shù)了(看下面的代碼變化),你要在btn上綁定debounce事件就要在debounce里面將改造好的changeColor事件寫成一個回調(diào)函數(shù)。

// btn.addEventListener('click', changeColor, false);
btn.addEventListener('click', debounce(changeColor), false);

2. 這個 let t = null; 豈不是會每次都將 t 置為 null ??這可咋實現(xiàn)呢?

 解:你以為 btn 綁定的是 debounce,所以你認為每次觸發(fā)都會執(zhí)行 t = null。

漏! btn 綁定的是debounce(changeColor)!這個括號不可忽視,實際上每次觸發(fā)click事件執(zhí)行的是它的回調(diào),也就是 return 里面的內(nèi)容,let t = null 只會在初始化的時候執(zhí)行一次。

雖然目前已經(jīng)實現(xiàn)了防抖的效果,但是這么寫的話,你會發(fā)現(xiàn)changeColor函數(shù)是拿不到事件對象的,也就是說它拿不到本該屬于它的 event 。

要想讓它拿回本該屬于它的 event ,你可以這么做: 

1.基于當前 event 已經(jīng)在 debounce 上了,你可以將 e 當參數(shù)傳遞給 debounce 里回調(diào)的函數(shù)

2.再把e傳給回調(diào)函數(shù)中定時器里的 fn() ,即 fn(e)

function debounce(fn) {
            let t = null
            //往這里傳e
            return function (e) {
                if (t) {
                    clearTimeout(t)
                }
 
                t = setTimeout(function() {
                    //再帶給fn
                    fn(e)
                }, 1000)
            }
        }

屆時,你就會發(fā)現(xiàn) changeColor 它拿到了事件對象! 

 如果你問,非要拿這個e干啥呢??

那么我只能說,拿到了e可以對e做一些操作(像是e.target可以更改等等),如果你不對e做什么不傳給它也沒關(guān)系,只是這么寫可以離一個完美的防抖函數(shù)更近而已。

但是你不能保證只有一個參數(shù)需要傳給 changeColor ,所以在傳參的時候只寫一個 e 沒辦法實現(xiàn)多個參數(shù)的傳遞,那么為了更完美一點,我們接著來改改。

說到多個參數(shù)的傳遞你大概會想到實參列表 arguments 。沒錯!就是它!

如果你不了解 arguments,請前往:學arguments去嘍

 arguments對象是所有(非箭頭)函數(shù)中都可用的局部變量。你可以使用arguments對象在函數(shù)中引用函數(shù)的參數(shù)。此對象包含傳遞給函數(shù)的每個參數(shù),第一個參數(shù)在索引0處。

首先,我們試著用 arguments[0] 去代替剛剛傳遞的 e ,你會發(fā)現(xiàn):

 那個return里的 arguments[0] 根本傳不到定時器里,那就更別提傳到 changeColor 了。

因為每個函數(shù)里的 arguments 都是自己函數(shù)內(nèi)部的,定時器里的函數(shù)沒有 arguments 所以 undefined。

要解決這個問題的話,你可以使用賦值的方式把 arguments 存下來,還可以使用箭頭函數(shù)。

接下來采用箭頭函數(shù)的方式來解決:

因為箭頭函數(shù)內(nèi)部沒有 arguments 對象,它會往外找,這樣就可以得到 return 里的 arguments。

function debounce(fn) {
            let t = null
            return function () {
                console.log('我是回調(diào)的arguments',arguments[0]);
                if (t) {
                    clearTimeout(t)
                }
                
                //這里用箭頭函數(shù)
                t = setTimeout(() => {
                    fn(arguments[0])
                    console.log('我是定時器里的arguments', arguments[0])
                    // console.log(this)
                }, 1000)
            }
        }

 這樣子就實現(xiàn)了 arguments[0] 的傳遞問題,如果是多個參數(shù)的話可以使用 apply 方法 將整個 arguments 作為參數(shù)傳遞過去,如下:

function debounce(fn) {
            let t = null
            return function () {
                if (t) {
                    clearTimeout(t)
                }
 
                t = setTimeout(() => {
                    fn.apply(this, arguments)                    
                }, 1000)
            }
        }

其中,apply方法的第一個參數(shù)還可以將 changeColor 的 this 由 Window 轉(zhuǎn)為 btn,屬于是一個一舉兩得的大動作了。 (因為箭頭函數(shù)會往外找this繼承,所以拿到了return里的this再傳給changeColor)

如果你不了解apply,請前往:學apply去嘍

寫到這里,一個 延遲debounce 就誕生了!

什么是延遲debounce??

顧名思義,在延遲結(jié)束那一刻才觸發(fā)回調(diào)。

如果你覺得每次按完按鈕還要等等才能改顏色真是太煩了,估計沒等到改顏色你就關(guān)閉網(wǎng)頁了。

前緣debounce 可以解決這個問題?。丛诙〞r器開始的那一刻就觸發(fā)事件)

將代碼再改一改你就可以得到 前緣debounce 啦!

function debounce(fn) {
            let t = null
            return function () {
                // 用firstClick來記錄每一次定時器開始的第一次按下的動作
                var firstClick = !t
 
                if(t) {
                    clearTimeout(t)
                }
 
                if(firstClick) {
                    fn.apply(this, arguments)
                }
 
                //等待1秒后將 t 置為 null,在這1秒內(nèi)如果再點擊事件就會去到if(t)的執(zhí)行
                t = setTimeout(() => {
                    t = null
                }, 1000)
            }
        }

這個前緣debounce將會實現(xiàn)每次連續(xù)點擊后先響應一次事件,再去等1秒。

總結(jié)

到此這篇關(guān)于js防抖具體實現(xiàn)以及詳細原理步驟的文章就介紹到這了,更多相關(guān)js防抖實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript中的DOM遍歷詳解

    JavaScript中的DOM遍歷詳解

    文檔對象模型 (DOM) 表示 HTML 文檔的結(jié)構(gòu),導航或“遍歷”此結(jié)構(gòu)是 Web 開發(fā)的基本方面,使開發(fā)人員能夠在網(wǎng)頁上選擇、修改、刪除或添加內(nèi)容,本文深入研究了使用 JavaScript 進行 DOM 遍歷的藝術(shù),提供了一個強大的工具包來處理各種遍歷場景
    2023-09-09
  • JS中promise化微信小程序api

    JS中promise化微信小程序api

    這篇文章主要給大家通過代碼實例分析了promise化微信小程序api的使用方法,對此有需要的朋友可以參考學習下。
    2018-04-04
  • js獲取指定日期前后的日期代碼

    js獲取指定日期前后的日期代碼

    js獲取指定日期前后的日期,在實際應用中還是比較實用的,下面為大家簡單介紹下具體的實現(xiàn)過程,有需要的朋友可以參考下
    2013-08-08
  • js Firefox 加入收藏夾功能代碼 兼容Firefox 和 IE

    js Firefox 加入收藏夾功能代碼 兼容Firefox 和 IE

    最近改用Firefox后,發(fā)現(xiàn)很多網(wǎng)站的“加入收藏”鏈接點擊無效了,后來發(fā)現(xiàn)原來是IE瀏覽器和Firefox瀏覽器的“加入收藏夾”的寫法是不同的。
    2009-12-12
  • js中 計算兩個日期間的工作日的簡單實例

    js中 計算兩個日期間的工作日的簡單實例

    下面小編就為大家?guī)硪黄猨s中 計算兩個日期間的工作日的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • JavaScript中的Proxy-Reflect操作方法

    JavaScript中的Proxy-Reflect操作方法

    這篇文章主要介紹了JavaScript中的Proxy-Reflect操作方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-11-11
  • JS實現(xiàn)title標題欄文字不間斷滾動顯示效果

    JS實現(xiàn)title標題欄文字不間斷滾動顯示效果

    這篇文章主要介紹了JS實現(xiàn)title標題欄文字不間斷滾動顯示效果,通過javascript時間函數(shù)定時操作動態(tài)修改頁面元素實現(xiàn)滾動效果,需要的朋友可以參考下
    2016-09-09
  • PHP中CURL的幾個經(jīng)典應用實例

    PHP中CURL的幾個經(jīng)典應用實例

    這篇文章主要介紹了PHP中CURL的幾個經(jīng)典應用實例,本文講解了cURL請求的基本步驟、在cURL中用POST方法發(fā)送數(shù)據(jù)、用cURL上傳文件等內(nèi)容,需要的朋友可以參考下
    2015-01-01
  • JavaScript中交換值的10種方法總結(jié)

    JavaScript中交換值的10種方法總結(jié)

    這篇文章主要給大家總結(jié)介紹了JavaScript中交換值的10種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者使用JavaScript具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2020-08-08
  • JavaScript實現(xiàn)三級聯(lián)動菜單實例代碼

    JavaScript實現(xiàn)三級聯(lián)動菜單實例代碼

    這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)三級聯(lián)動菜單實例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06

最新評論

南宫市| 固镇县| 察雅县| 定结县| 宁河县| 凤山市| 关岭| 井陉县| 保亭| 尼勒克县| 鄂托克旗| 屏东县| 古浪县| 左贡县| 濮阳市| 余干县| 格尔木市| 桂林市| 乐清市| 霍林郭勒市| 宿州市| 莎车县| 胶南市| 城口县| 梅河口市| 靖远县| 博野县| 延津县| 金堂县| 高台县| 凤阳县| 上林县| 宾阳县| 红原县| 曲麻莱县| 廊坊市| 永安市| 山丹县| 贵德县| 济阳县| 神木县|