利用函數式編程封裝節(jié)流和防抖函數

一、函數式編程定義

"函數式編程"是一種編程范式,也就是如何編寫程序的方法論。主要思想是把運算過程盡量寫成一系列嵌套的函數調用。即函數式編程要求使用函數,把運算過程定義為不同的函數。

二、函數式編程特性

  • 無副作用
  • 不可變數據
  • 純函數
  • 函數組合
  • 函數柯里化

三、看個栗子

計算若干個數之和:

function add(x, y) {
    return x + y;
}
function Reduce(...args) {
    // 返回值
    return args.reduce(add);
}

console.log(Reduce(1,2,3));

計算若干數之間的乘積:

function mul(x, y) {
    return x * y;
}
function Reduce(...args) {
    // 返回值
    return args.reduce(mul);
}

console.log(Reduce(1,2,3));

若干個數組的拼接:

function concat(x, y) {
    return x.concat(y);
}
function Reduce(...args) {
    // 返回值
    return args.reduce(concat);
}

console.log(Reduce([1,2],[5,6]));

可以看到,如果我們還有更多類似函數,我們還得對 Reduce 函數進行改寫。

至此,我們完全可以一次性抽取出一個通用的版本 Reduce :

function Reduce(fn) {
    return function (...args){
        return args.reduce(fn.bind(this));
    }
}
let add = Reduce((x, y) => x + y);
// wrong: let add = iterative((x, y) =>{ x + y});
console.log(add(1,2,3));

通過向 Reduce 方法中傳遞一個特定功能的函數,來返回一個具備增強能力的新函數。這樣我們可以像操作數據那樣操作一組函數,使得這些函數具備某些新的能力。

這就是過程抽象的基本思想。這些變換函數的函數我們稱之為“高階函數”(它們自身輸入函數或返回函數)。

四、過程抽象的具體應用

  1. 控制函數調用的頻率
  • 只調用一次的情況 (exp: 觸發(fā)點擊事件的回調函數限制其只調用一次)
function once(fn) {
    return function (...args) {
        if(fn) {
            let res = fn.apply(this, args);
            fn = null;
            return res;
        }
    }
}

function foo(idx) {
    console.log(idx);
}

foo(1);
foo(2);
foo(3);

let foo = once(foo);
foo(11);
foo(22);
foo(33);

場景代碼:https://code.h5jun.com/buzi/2/edit?html,js,output

  • 每隔一定的時間觸發(fā)函數的執(zhí)行;

節(jié)流:常用來防止按鈕被重復點擊,防止 resize、scroll 和 mousemove 事件過于頻繁地觸發(fā)等。

這種方式也可避免定義全局的定時器變量,不會污染該變量。

function throttle(fn, wait=500) {
    let timer;
    return function (...args) {
        if(timer == null) { // undefined == null // true undefined === null //false 這里不要寫成 嚴格相等 不然永遠執(zhí)行不進去
            timer = setTimeout(() => timer = null, wait)
            return fn.apply(this, args);
        }
    }
}
//限制button在500ms內只能被點擊一次:
//快速連續(xù)不停的點擊,按鈕只會有規(guī)律的每500ms點擊有效
button.addEventListener('click', throttle(() => {
    console.log('hhh')
}))

// function once(fn) {
//  fn = null; 不會改變外部的實參
//}
//function hh(){alert(11)}
//once(hh)
//console.log(hh)// function hh(){alert(11)}
// 類似于
function a(o){
  o = 1; // o.aa = 22;
}
var obj = {
    aa: 11
}
a(obj);
console.log(obj);

防抖動:希望函數在某些操作執(zhí)行完成之后被觸發(fā)。
輸入框搜索數據時,為了限制從服務器讀取數據的頻率,我們可以等待用戶輸入結束 100ms 之后再觸發(fā)查詢;或者點擊提交按鈕獲取數據,防止頻繁的請求數據,限制用戶提交完一段時間后再請求數據。(想想這里防抖動與上面節(jié)流的區(qū)別)

function debounce(fn, wait=500) {
    let timer;
    return function (...args) {
        if(timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(() => {
            timer = null;
            return fn.apply(this, args)
        }, wait)
    }
}
// 快速連續(xù)不停的點擊,永遠不會觸發(fā),直到停止點擊,函數被執(zhí)行一次
button.addEventListener('click', debounce(() => {
    console.log('hhh');
    getMoreData();
}))

節(jié)流和防抖動都是控制函數在一定時間內的執(zhí)行次數,例如規(guī)定的時間間隔是500ms,如果連續(xù)在小于這個時間間隔內調用防抖動函數,該函數永遠不會被執(zhí)行(直到停止點擊,觸函數觸發(fā)一次);而節(jié)流函數會在每到達一段間隔的時間內有規(guī)律的被執(zhí)行。

詳見一句話說清楚.throttle和.debounce的區(qū)別

References

函數式編程離我們有多遠?
一句話說清楚.throttle和.debounce的區(qū)別
實例解析防抖和節(jié)流函數

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容