JS - 函数防抖详解

发布于:2025-06-10 ⋅ 阅读:(19) ⋅ 点赞:(0)

一、使用场景

  • 函数内执行耗时操作
  • 函数执行不频繁,只有最后一次有意义
  • 举例:鼠标移动事件,键盘输入事件…等需要逻辑处理时

二、实现思路(详解,es6之前版本)

举例场景为键盘输入事件,函数内部通过apply改变this指向,通过slice处理arguments(参数集)伪数组

  1. 前置
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>函数防抖</title>
</head>
<body>
    <input type="text">
</body>
<script>
    var input = document.querySelector('input');
    input.addEventListener('input', function(e) {
        console.log(e.target.value);
    });
</script>
</html>
  1. 实现延时触发效果 – 使用高阶函数思想封装函数
    高阶函数(至少满足以下条件之一):1.接受一个或多个函数作为参数。2.返回一个新的函数。
	function debounce(fn, delay) {
        return function() {
            setTimeout(() => {
                fn();
            }, delay);
        }
    }
    var newFn = debounce(function() {
        console.log(111);
    }, 1000);
    var input = document.querySelector('input');
    input.addEventListener('input', newFn);
  1. 实现只响应最后一次触发 – 利用setTimeout返回值进行处理
    这里将this改为打印内容,我们可以发现this为undefined。
    原因:函数的this指向调用者,那么当前fn是在setTimeout中调用,指向全局
	function debounce(fn, delay) {
        var timer = null;
        return function() {
            clearTimeout(timer);
            timer = setTimeout(() => {
                fn();
            }, delay);
        }
    }
    var newFn = debounce(function() {
        console.log(this);
    }, 1000);
    var input = document.querySelector('input');
    input.addEventListener('input', newFn);
  1. 实现this绑定和参数传递
    arguments:函数调用时传入的所有参数(伪数组)
	function debounce(fn, delay) {
        var timer = null;
        return function() {
            clearTimeout(timer);
            timer = setTimeout(() => {
                var args = Array.prototype.slice.call(arguments,0); // 伪数组转化
                fn.apply(this,args);
            }, delay);
        }
    }
    var newFn = debounce(function(e) {
        console.log(this.value,e);
    }, 1000);
    var input = document.querySelector('input');
    input.addEventListener('input', newFn);
  1. 自定义参数传递
	function debounce(fn, delay) {
        var timer = null;
        return function() {
            clearTimeout(timer);
            timer = setTimeout(() => {
                var args = Array.prototype.slice.call(arguments,0);
                fn.apply(this,args);
            }, delay);
        }
    }
    var newFn = debounce(function(e,a) {
        console.log(e,a);
    }, 1000);
    var input = document.querySelector('input');
    input.addEventListener('input', (e)=>{
        newFn(e,1);
    });

三、es6实现

使用箭头函数、解构赋值、剩余参数等现代 JavaScript 特性
!!!箭头函数没有自己的 this,它会继承定义时所在作用域的 this

	const debounce = (fn, delay) => {
        let timer = null;
        return function(...args) {
            clearTimeout(timer);
            timer = setTimeout(() => {
                fn.apply(this, args);
            }, delay);
        }
    }

    const newFn = debounce(function(e) {
        console.log(e, this.value);
    }, 1000);

    const input = document.querySelector('input');
    input.addEventListener('input', newFn);

四、第三方库

lodash中文官网