- A+
所属分类:Web前端
高阶函数
函数柯里化
函数柯里化,又称部分求值。一个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; }