这是我参与「第四届青训营 」笔记创作活动的第9天
1.高阶函数Once
-
高阶函数:以函数作为参数或者以函数作为返回值的函数称为高阶函数
- 同时满足两个条件的函数常用于作为函数装饰器
-
function once(fn) { return function(...args) { if(fn) { const ret = fn.apply(this, args); fn = null; return ret; } } }- once函数接收到的参数是一个fn函数,返回的是一个新的函数
- 在返回的函数中,只让fn执行一次,第二次执行的时候fn已经被赋值为null,就无法再次被执行了
-
const foo = once(() => { console.log('bar'); }); foo(); foo(); foo(); button.addEventListener('click', once((evt) => { const target = evt.target; target.parentNode.className = 'completed'; setTimeout(() => { list.removeChild(target.parentNode); }, 2000); })); -
这样,我们就将一次执行这个过程抽象出来了,任何需要一次执行的函数,只要在外面包一层once就可以实现,我们可以把once成为函数装饰器。
扩展:
- JS数组的哪些API是高阶函数:every、map、filter、forEach、reduce、sort
2.高阶函数HOF
-
HOF
- 以函数作为参数
- 以函数作为返回值
- 常用于作为函数装饰器
function HOF0(fn) { return function(...args) { return fn.apply(this, args); } } -
fn与HOF0(fn)是完全等价的,无论参数、调用上下文怎么变化,他们都是等价的! 也就是说,执行fn与执行HOF0(fn)没有任何区别 -
可以看出我们的Once函数就是在HOF0上进行拓展出来的
3.高阶函数Throttle
-
可以定义节流函数
function throttle(fn, time = 500){ let timer; return function(...args){ if(timer == null){ fn.apply(this, args); timer = setTimeout(() => { timer = null; }, time) } } } //效果,连续多次点击只会每500ms记录一次 btn.onclick = throttle(function(e){ circle.innerHTML = parseInt(circle.innerHTML) + 1; circle.className = 'fade'; setTimeout(() => circle.className = '', 250); });
4.高阶函数debounce
-
定义防抖函数
function debounce(fn, dur){ dur = dur || 100; var timer; return function(){ clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, arguments); }, dur); } }
5.consumer函数
-
function consumer(fn, time){ let tasks = [], timer; return function(...args){ tasks.push(fn.bind(this, ...args)); if(timer == null){ timer = setInterval(() => { tasks.shift().call(this) if(tasks.length <= 0){ clearInterval(timer); timer = null; } }, time) } } }- 相当于将同步操作变成一个异步的操作
-
用法1 逐步累加
function add(ref, x){ const v = ref.value + x; console.log(`${ref.value} + ${x} = ${v}`); ref.value = v; return ref; } //相当于是consumer化的add,这样就可以实现类似于异步的效果,相隔一秒执行一次add let consumerAdd = consumer(add, 1000); const ref = {value: 0}; for(let i = 0; i < 10; i++){ consumerAdd(ref, i); } -
用法2 连击异步增加(快速点击慢慢执行)
btn.onclick = consumer((evt)=>{ let t = parseInt(count.innerHTML.slice(1)) + 1; count.innerHTML = `+${t}`; count.className = 'hit'; let r = t * 7 % 256, g = t * 17 % 128, b = t * 31 % 128; count.style.color = `rgb(${r},${g},${b})`.trim(); setTimeout(()=>{ count.className = 'hide'; }, 500); }, 800)
6.iterative函数
-
function iterative(fn) { return function(subject, ...rest) { if(isIterable(subject)) { const ret = []; for(let obj of subject) { ret.push(fn.apply(this, [obj, ...rest])); } return ret; } return fn.apply(this, [subject, ...rest]); } }