防抖、节流、柯里化

621 阅读2分钟

前言

开发中常见的开发技巧、面试中长谈的设计模式,自然少不了这三个兄弟了~

防抖

应用场景:

  • 按钮点击防止多次触发
  • 下拉框输入监听延迟搜索功能
  • window.onresize 监听窗口变化
/**
 * @desc 函数防抖
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param immediate true 表立即执行,false 表非立即执行
 */
function debounce(func,wait,immediate) {
    let timeout;

    return function () {
        let context = this;
        let args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            var callNow = !timeout;
            timeout = setTimeout(() => {
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        } else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
}

节流

应用场景:

  • 滚动条监听
  • 上拉加载获取数据
/**
 * @desc 函数节流
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param type 1 表时间戳版,2 表定时器版
 */
function throttle(func, wait ,type) {
    if(type===1){
        let previous = 0;
    }else if(type===2){
        let timeout;
    }
    return function() {
        let context = this;
        let args = arguments;
        if(type===1){
            let now = Date.now();

            if (now - previous > wait) {
                func.apply(context, args);
                previous = now;
            }
        } else if(type===2){
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null;
                    func.apply(context, args)
                }, wait)
            }
        }
    }
}

柯里化

柯里化说实话第一次听到的时候,感觉很奇妙,很高级,但实际上理解了含义后,其实也没什么大不了的呀~

官方介绍:

柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

这段话还是直接看代码来理解吧~

简单应用

// 函数封装后
function check(reg, txt) {
    return reg.test(txt)
}

check(/\d+/g, 'test')       //false
check(/[a-z]+/g, 'test')    //true

// Currying后
function curryingCheck(reg) {
    return function(txt) {
        return reg.test(txt)
    }
}

var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)

hasNumber('test1')      // true
hasNumber('testtest')   // false
hasLetter('21212')      // false

从这里可以看出来,其本质就是用了闭包,相当于一个工厂模式,对特定规则进行加工,产出对应功能的工具。

最常见的应用就是 Function.prototype.bind 就是典型的柯里化了

那有一个问题,关于官方描述的,可能需要满足于这种需求:

通用封装实现 currying(a)(b)(c) 模式

这里本人按照要求完成了下面一个小栗子:

function createCurrying(fn) {
    var _this = this
    var len = fn.length;
    var args = Array.prototype.slice.call(arguments, 1);

    return function() {
        var newArgs = args.concat(Array.prototype.slice.call(arguments));
        var _args = [];
        
        for (var i = 0; i < newArgs.length; i += 1) {
            _args.push('newArgs[' + i + ']');
        }

        // 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
        if (newArgs.length < len) {
            return eval('createCurrying.call(_this, fn, ' + _args + ')')
        }

        // 参数收集完毕,则执行fn
        return fn.apply(this, newArgs);
    }
}

var currying = createCurrying(
        function (a,b,c,d) { console.log(a,b,c,d) }, '1', '2'
    );
    
currying('3')('4'); // 输出: 1, 2, 3, 4