高阶函数
函数柯里化
函数柯里化,又称部分求值。一个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;
}