高阶函数

  • A+
所属分类:Web前端
摘要

函数柯里化,又称部分求值。一个currying函数首先会接收一些参数,接受这些参数后该函数不会立即求值。而是会将传入的参数在函数内保存,待函数真正需要求值时,之前的所有参数都会被一次性用于求值


高阶函数

函数柯里化

函数柯里化,又称部分求值。一个currying函数首先会接收一些参数,接受这些参数后该函数不会立即求值。而是会将传入的参数在函数内保存,待函数真正需要求值时,之前的所有参数都会被一次性用于求值

非柯里化

var mothlyCost = 0;   var cost = function(money:number) {    mothlyCost += money;  }   cost(100);  cost(200);  cost(300);  cost(400);   console.log(mothlyCost); 

柯里化实现

function sum(args: Array<number>) {   // 没有这个参数,就开始计算结果返回   let count = 0;    args.forEach(item => {     count += item;   })    return count; }   // 简单柯里化 var curringCost = function(): any {   let args:Array<number> = [];     return function(money?: number){       if(money) {         // 如果有这个参数,就讲数据添加到参数数组中         args.push(money);        } else {         return sum(args);       }   }  }  // 先初始化 let testCost = curringCost(); testCost(100); testCost(200); testCost(300); testCost(400); console.log(testCost()); 

最后我们来给写一个函数,让其可以未其他函数提供柯里化的能力

套壳柯里化

// 柯里化外套 let comCurring = function(fn:Function){    var args:Array<any> = [];     return function(money?: number){       if(arguments.length > 0){        // 有参数,保存,不做其他操作        args.push(...arguments);      } else {        // 无参数,使用参入fn对数据处理        return fn.apply(this, args);      }    } }  // 先初始化 let sumCost = comCurring(sum); sumCost(100); sumCost(200); sumCost(300); sumCost(400); console.log(sumCost()); 

反柯里化

interface Function {   uncurrying: () => (obj:any, number: any) => {}; }   Function.prototype.uncurrying = function(){       // 将this指针保留下来       let self = this;        // 返回一个匿名函数被“push”接收了       return function() {         /**          * push(currentObj, 5)          * 获取第一个参数,也就是需要执行的对象(currentObj)          * 这个时候arguments就只剩下“5”这个变量了          */         let obj = Array.prototype.shift.call(arguments);          /**          * 执行这个方法,注意这个方法是由谁调用的          * 在这个案例中,这个匿名函数是被Array的push方法调用的          * 所以这里的self为push这个方法          */         return self.apply(obj, arguments);       }   }    // 提取push方法   const push  = Array.prototype.push.uncurrying();   let currentObj = {     0 : 1,     length : 1   }    push(currentObj, 5);   console.log(currentObj) 

分时函数

/**  * 分时函数  * 将数据分批操作  * 例子:渲染1000个好友  */ function timeSharing<T>(arr:Array<T>, fn:Function,  count:number, time:number) {      function strat(){       let index = 0,           len = Math.min(arr.length, count);       for (; index < len; index++) {         const element = arr.shift();         fn(element);       }     }        let timer = setInterval(() => {       if(arr.length === 0) {         return clearInterval(timer);        }       strat();     }, time) }  let arr = []; for (let index = 0; index < 1000; index++) {    arr.push(index); } timeSharing(arr, function(num: number){   console.log(num) }, 10, 200);  

惰性加载

其实我觉得这个还是比较勤快,也许是聪明的懒惰。如果方法里有判断,就先加载方法,后面就不需要再进行判断了,下面模拟 浏览器嗅探

  • if A浏览器 使用 aTest方法

  • if B浏览器 使用 bTest方法

公共代码

// 全局控制变量,模拟不同浏览器 const GLOBAL_CONTROL = "A";   function aTest(){   console.log("A浏览器中使用") }  function bTest(){   console.log("B浏览器中使用") } 

基础版

/**  * 简版  * 需要使用if判断,每次执行都需要  */ function compatibleFunction() {   if(GLOBAL_CONTROL === "A") {     aTest();   } else {     bTest();   } } compatibleFunction();  console.log(compatibleFunction) 

先行版

/**  * 惰性加载函数 先行版  * 避免了每次判断,只需要开始的时候执行一遍即可  * 但是如果项目中没有用到,那这个方法就累赘并且还占用了启动时间  */ let lazyCompatibleBefore = (function() {   if(GLOBAL_CONTROL === "A") {     return aTest;   } else {     return bTest;   } })() lazyCompatibleBefore();  console.log(lazyCompatibleBefore) 

懒加载版

/**  * 惰性加载函数 懒加载版  * 避免了每次判断,执行一遍完第一遍后就是以后都是正常方法  * 中间将方法替换为正确版本的方法  * 最后记得再执行一遍,不然第一次就相当于只做了替换  */ let lazyCompatibleRuntime = function() {    if(GLOBAL_CONTROL === "A") {     lazyCompatibleRuntime = aTest;   } else {     lazyCompatibleRuntime = bTest;   }      lazyCompatibleRuntime(); }  console.log(lazyCompatibleRuntime) lazyCompatibleRuntime(); console.log(lazyCompatibleRuntime) 

节流函数

/**  * 节流函数  * 通用的节流函数  * @param fn       需要节流的函数  * @param time     节流时间  * @param isFrist  第一次是否立即执行  */ function throttlingWrapper(fn:Function, time:any, isFrist = true) {   var timer:any = null,       _self = fn;     let throtting = () => {       let _me:any = this;      // 如果timer有值,也就是还在执行中,则直接返回     if(timer){       return;     }       // 是否首次触发     if(isFrist){       _self.apply(_me, arguments);       isFrist = false;       return;     }      // 节流函数本体     timer = setTimeout(() => {       _self.apply(_me, arguments);       clearTimeout(timer);       timer = null     }, time)   }     return throtting; }