柯里化 柯里化又称为部分求值。一个 柯里化的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
简单来说就是实现这样的效果: add(1)(2, 3)(4)(5) = 15 
实现一个简单的柯里化函数并不困难,我们要做只有两点
用闭包保存之前传入的参数 
在每次传入参数后判断是否已经收集了足够多的参数,如果是就执行函数 
 
来看看代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function  curry (targetFun, targetLength, targetThis ) {         targetLength = (targetLength >= 0  ? targetLength : 0 ) ''  targetFun.length ;          const  allArgs = [];          const  wait = function  (...arg ) {                  allArgs.push (...arg);                  if  (allArgs.length  >= targetLength){             return  targetFun.apply (targetThis, allArgs);         } else  {             return  wait;         }     };     return  wait; } 
 
可以看到代码实现并不复杂,至于为什么要传入targetLength呢,一方面是为了更灵活地处理收集个数问题,另一个就是用Function.length判断参数个数可能会造成意料之外的结果
根据MDN的定义,函数参数会排除掉带收集运算符(…)的参数,并只统计第一个有默认数据的参数前的参数个数。
1 2 3 4 console .log ((function (...args ) {}).length ); console .log ((function (a, b = 1 , c ) {}).length );
 
柯里化有什么应用呢,其实一时半会我也想不出来……因为这只是一种优化策略…..想到再补充
防抖 防抖函数是一种只在最后一次会触发防抖函数的操作结束一段时间后后才会执行的函数,举个通俗易懂的例子,在你使用百度搜索框的时候,如果你输入字符的速度比较快,就会发现候选词列表的更新是在你输入完一串此之后才更新的,而不是输入一个字符更新一次,这算是防抖函数一个很经典的应用。或者生活中的一个很经典的场景,公交车的车门是在所有人都进入后,等待一段时间后发现没有人继续上车才关闭的,这也算一种防抖。
防抖函数的实现思路比较简单,只要设置一个定时器,在定时器内部执行真正要执行的函数,如果防抖函数再次被执行,就取消定时器,然后再次设置一个相同的计时器重新开始计时。代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function  debounce (handler, delay ) {         let  timer = null ;     return  function  ( ) {         const  self = this ;         const  args = arguments ;                  clearTimeout (timer);         timer = setTimeout (function  ( ) {                          handler.apply (self,args);         },delay);     } } 
 
节流 节流的目的是,让一个函数被调用后,要到一段时间后才能再次被调用,防止过高频率的调用。具体的应用有,降低一些过于频繁的事件比如window.onresize,mousemove事件这样的触发频率,还有就是防止某些脚本(笑),因为之前听到过阿里工程师写脚本抢月饼券抢了几千张的故事233,这肯定是发AJAX的函数没做点什么处理
来看看节流函数的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function  throttle (handler, time ) {    let  preTime = 0 ;     let  curTime = 0 ;     return  function  (...args ) {                  curTime = new  Date ().getTime ();                  if  (curTime - preTime > time){             handler.apply ( this , args);                          preTime = curTime;         }     } } 
 
实现起来比较简单,但是有个问题,就是如果最后一次执行真正函数的时间和最后一次触发节流函数的时间差过短,就可能导致最后一次触发被忽略,这就有可能带来一些bug,比如要把窗口的大小实时显示在html中,如果最后一次绑定的onresize的真正的处理函数没有被执行,就可能导致显示的数值不对,所以我们要稍微处理一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function  throttle (handler, time ) {    let  preTime = 0 ;     let  curTime = 0 ;     let  timer = null ;     return  function  (...args ) {                  curTime = new  Date ().getTime ();                  clearTimeout (timer);                  if  (curTime - preTime > time){             handler.apply ( this , args);                          preTime = curTime;         } else  {                          timer = setTimeout (() =>  {                 handler.apply (this , args);             }, time);         }     } } 
 
从代码中可以看出,如果该次代码没有执行,就设置一个定时器,如果下次触发节流函数的时间小于规定时间,取消定时器,重新计数,否则执行回调,这样就保证了最后一次调用一定可以执行到真正的回调函数。