一些JavaScript高阶函数
函数柯里化
'use strict'; function currying(fn) { const args = []; // 收集传入的参数 const curred = function () { if (!arguments.length) return fn.apply(this, args); // 没有参数再指向 Array.prototype.push.apply(args, arguments); return curred; }; return curred; } const plus = (...args) => args.reduce((pre, cur) => pre + cur, 0); const plusCurred = currying(plus); plusCurred(1)(2)(3); plusCurred(4); console.log(plusCurred()); // 10
将函数附加在 Function 上, 实现一步转为柯里化(骚操作)
'use strict'; Function.prototype.currying = function () { const fn = this; const args = []; // 收集传入的参数 const curred = function () { if (!arguments.length) return fn.apply(this, args); // 没有参数再指向 Array.prototype.push.apply(args, arguments); return curred; }; return curred; }; const plus = (...args) => args.reduce((pre, cur) => pre + cur, 0); const plusCurred = plus.currying(); plusCurred(1)(2)(3); plusCurred(4); console.log(plusCurred()); // 10
反柯里化
'use strict'; Function.prototype.unCurrying = function () { let self = this; return function () { return Function.prototype.call.apply(self, arguments); }; }; const push = Array.prototype.push.unCurrying(); const t1 = [1, 2, 3]; push(t1, 4); console.log(t1); // [ 1, 2, 3, 4 ] // 定义 length 的对象都可以用 Array.prototype.push const t2 = { length: 2 }; Array.prototype.push.call(t2, 4); console.log(t2); // { '2': 4, length: 3 } // unCurrying 简化了调用 const t3 = { length: 2 }; push(t3, 4); console.log(t3);
节流
function throttle(fn, interval = 500) { let timer = null, first = true; return function () { if (first) return fn.apply(this, arguments); // 首次不卡 if (timer) return false; // 在 interval 内还有其他函数在执行 timer = setTimeout(() => { fn.bind(this, arguments); clearTimeout(timer); timer = null; }, interval); }; }
防抖
function debounce(fn, wait) { var timer = null; return function () { var context = this, args = arguments; if (timer) { clearTimeout(timer); timer = null; } timer = setTimeout(() => { fn.apply(context, args); }, wait); }; } // test var debounceRun = debounce(function () { console.log(123); }, 2000); window.addEventListener('mousemove', debounceRun);
注意防抖不要被饿死(抖死), 尤其要防止与时间相关的元素打交道, 比如我设置了 500ms 的防抖, 结果有一个视频播放模块要调防抖, 这个视频播放模块每 24ms 就要执行一次, 直接抖死
装饰器
Function.prototype.before = function (fn) { const self = this; return function () { fn.apply(this, arguments); return self.apply(this, arguments); }; }; Function.prototype.after = function (fn) { const self = this; return function () { const res = self.apply(this, arguments); fn.apply(this, arguments); return res; }; }; const f1 = () => console.log(1); const f2 = () => console.log(2); const f = f1.after(f2).before(f2); f(); // 2 1 2