VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 网站开发 > JavaScript教程 >
  • 高阶函数

高阶函数

函数柯里化

函数柯里化,又称部分求值。一个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;
}
如果对你有帮助,下次再见,嘻嘻
 
出处:https://www.cnblogs.com/wangzhaoyv/p/14403971.html

相关教程