一个函数如果有 参数是函数 或 返回值是函数,就称为高阶函数。

这篇文章介绍高阶函数的一个子集:输入 fn,输出 fn'。按 fnfn' 功能是否一致,即相同输入是否始终对应相同输出,把这类高阶函数的作用分为两种:

  1. 包装函数:功能一致
  2. 修改函数:功能不一致

包装函数

从斐波那契数列开始。

const fib = n =>
n <= 1 ? 1 : fib(n - 1) + fib(n - 2); fib(42);

记录执行时间

  • 普通青年

    const fib = n =>
    n <= 1 ? 1 : fib(n - 1) + fib(n - 2); console.time("fib");
    fib(42);
    console.timeEnd("fib");
  • 函数式青年

    const timed = fn => (...args) => {
    console.time(fn.name);
    const result = fn(...args);
    console.timeEnd(fn.name);
    return result;
    };
    const fib = n =>
    n <= 1 ? 1 : fib(n - 1) + fib(n - 2); timed(fib)(42);

优化性能

  • 普通青年

    const memory = {};
    const fib = n => {
    if (n <= 1) return 1;
    else {
    if (memory[n]) return memory[n];
    else {
    memory[n] = fib(n - 1) + fib(n - 2);
    return memory[n];
    }
    }
    };
    const timed = fn => (...args) => {
    console.time(fn.name);
    const result = fn(...args);
    console.timeEnd(fn.name);
    return result;
    };
    timed(fib)(42);
  • 函数式青年

    const memoize = fn => {
    const memory = {};
    return arg => {
    if (memory[arg]) return memory[arg];
    else {
    memory[arg] = fn(arg);
    return memory[arg];
    }
    };
    };
    const fib = memoize(n =>
    n <= 1 ? 1 : fib(n - 1) + fib(n - 2)
    );
    const timed = fn => (...args) => {
    console.time(fn.name);
    const result = fn(...args);
    console.timeEnd(fn.name);
    return result;
    };
    timed(fib)(42);

修改函数

once

场景:

发送请求,如果后台返回 session 超时,弹出重新登录提示框。

发出多个请求,都 session 超时,只希望弹一个重新登录提示框。

const once = fn => {
let executed = false;
return (...args) => {
if (!executed) {
executed = true;
fn(...args);
}
};
};
const showLogoutWin = once(() => {
// ...
});

debounce

场景:

输入框 change 事件触发向后台查询。

为消除不必要查询,用户连续输入时不触发查询,

当 200ms 内没有新的输入时,才向后台查询。

const debounce = (fn, ms = 200) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn(...args), ms);
};
};

更多实际场景

validateRequired

场景:

根据 rule.required 判断空值时是否报错,

这段逻辑出现在多个 validator 中。

const ipv4Validator = (rule, value, callback) => {
if (value) {
if (ipv4RegExp.test(value)) {
callback();
} else {
callback("请输入合法IP");
}
} else {
if (rule.required) {
callback("该域为必填项");
} else {
callback();
}
}
};

把判空的逻辑提取到高阶函数中:

const validateRequired = (
validator,
msg = "该域为必填项"
) => (rule, value, callback) => {
if (value) {
validator(rule, value, callback);
} else {
if (rule.required) {
callback(msg);
} else {
callback();
}
}
}; const ipv4Validator = validateRequired(
(rule, value, callback) => {
if (ipV4Regexp.test(value)) {
callback();
} else {
callback("请输入合法IP");
}
}
);

tryUntilSucceeded

场景:

因为网络不稳定,请求可能出错。

出错后重新请求,直到得到响应为止。

let res;
while (true) {
try {
res = await get(path);
break;
} catch (err) {
console.log(err);
}
}

把出错重试的逻辑提取到高阶函数中:

const tryUntilSucceeded = fn => async (
...args
) => {
while (true) {
try {
return await fn(...args);
} catch (err) {
console.log(err);
}
}
}; const enhancedGet = tryUntilSucceeded(get);
const enhancedPost = tryUntilSucceeded(post); const resGet = await enhancedGet(path);
const resPost = await enhancedPost(path);

小结

两个代码块一样,把这个代码块提取出来,封成一个函数,减少代码重复,这个技巧大家都知道;两段代码流程一样,用高阶函数把公共流程提取出来,减少代码重复,这个技巧知道的人就不多了。可以类比 react 高阶组件,道理是一样的。

高阶函数 - Higher Order Function的更多相关文章

  1. Python进阶内容(一)--- 高阶函数 High order function

    0. 问题 # 本文将围绕这段代码进行Python中高阶函数相关内容的讲解 # 文中所有代码的兼容性要求为:Python 3.6,IPython 6.1.0 def addspam(fn): def ...

  2. 高阶函数(Higher-order function)

    变量可以指向函数 以Python内置的求绝对值的函数abs()为例,调用该函数用以下代码: >>> abs(-15) 15 但是,如果只写abs呢? >>> abs ...

  3. 匿名方法,Lambda表达式,高阶函数

    原文:匿名方法,Lambda表达式,高阶函数 匿名方法 c#2.0引入匿名方法,不必创建单独的方法,因此减少了所需的编码系统开销. 常用于将委托和匿名方法关联,例如1. 使用委托和方法关联: this ...

  4. 《JS权威指南学习总结--8.8.2高阶函数》

    内容要点: 所谓高阶函数(higher-order function)就是操作函数的函数,它接收一个或多个函数作为参数,并返回一个新函数. 例1: //这个高阶函数返回一个新的函数,这个新函数将它的实 ...

  5. python---内置函数,匿名函数,嵌套函数,高阶函数,序列化

    函数简单说明 # 函数即"变量" # 高阶函数 # a.把一个函数名当做实参传给另一个函数(在不修改被装饰函数的源代码的情况下,为其添加功能) # b.返回值中包含函数名(不修改函 ...

  6. 理解运用JS的闭包、高阶函数、柯里化

    JS的闭包,是一个谈论得比较多的话题了,不过细细想来,有些人还是理不清闭包的概念定义以及相关的特性. 这里就整理一些,做个总结. 一.闭包 1. 闭包的概念 闭包与执行上下文.环境.作用域息息相关 执 ...

  7. python的高阶函数与匿名函数

    一.高阶函数的定义 高阶函数:就是把函数当成参数传递的一种函数,例如: def add(x,y,f): return f(x)+f(y) print(add(-8,11,abs) 结果:19 解释: ...

  8. Javascript中的高阶函数介绍

    高阶函数:高阶看上去就像是一种先进的编程技术的一个深奥术语,一开始我看到的时候我也这样认为的. Javascript的高阶函数 然而,高阶函数只是将函数作为参数或返回值的函数.以下面的Hello,Wo ...

  9. Swift 烧脑体操(三) - 高阶函数

    前言 Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说更加困 ...

随机推荐

  1. 在Spring Boot中添加全局异常捕捉提示

    在一个项目中的异常我们我们都会统一进行处理的,那么如何进行统一进行处理呢? 全局异常捕捉: 新建一个类GlobalDefaultExceptionHandler, 在class注解上@Controll ...

  2. map.entrySet().iterator()

    1.首先创建一个HashMap, Map map= new HashMap(); 2.Iterator iter= map.entrySet().iterator(); 首先是map.entrySet ...

  3. http://t.cn/xxxxx的短链接如何生成?

    var convertStr = encodeURIComponent(urlStr); //转换的原链接可能存在"&"这样的特殊符号,导致原链接的某些字段会被当做ajax ...

  4. 顺序队列与链式队列--C语言实现

    关于队列,因为我自己在平时使用不多,所以在这里直接将队列的两种存储方式放在一起,作为一篇随笔,这两份代码均可直接运行,亲测.注释写的应该也算比较详细了,就不过多的解释了 顺序队列 #include&l ...

  5. java访问数据库被拒绝,不能连接数据库ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

    错误原因:mysql数据库只允许本地ip访问: 解决方法:修改mysql表设置所有ip都可以访问: 登录数据库 使用以下命令: use mysql; grant all privileges on * ...

  6. 【HUAWEI Mate30】抽奖啦!华为IoT新福利上线!

    华为云OceanConnect IoT云服务包括应用管理.设备管理.系统管理等能力,实现统一安全的网络接入.各种终端的灵活适配.海量数据的采集分析,从而实现新价值的创造. 华为云OceanConnec ...

  7. IoT开发精英实战营招募啦!速来报名!

    具有了向上的力量,才能一眼望到山外的大地,蜿蜒的长河,人类精神的进步. --罗曼·罗兰<爱与死的搏斗> 七月流火,八月未央,九月授衣.说是长长长长的夏天,眨眼间,也早过了立秋而迎来处暑.距 ...

  8. 华为OSPF与ACL综合应用

    一. 实验拓扑图 二.实验要求 1.企业内网运行OSPF路由协议,区域规划如图所示:2.财务和研发所在的区域不受其他区域链路不稳定性影响:3.AR1.AR2.AR3只允许被IT登录管理:4.YF和CW ...

  9. ASP.NET Core 选项模式源码学习Options IOptions(二)

    前言 上一篇文章介绍IOptions的注册,本章我们继续往下看 IOptions IOptions是一个接口里面只有一个Values属性,该接口通过OptionsManager实现 public in ...

  10. 使用Carthage集成Alamofire

    Carthage相较于Cocoapods有着使用灵活,对目标工程改动小的优势,使得它越来越受欢迎.今天就对我使用Carthage集成FBSDK做一个记录. 1.首先https://github.com ...