概念

《javascript设计模式和开发实践》中定义 函数既可作为参数被传递,也可以作为返回值输出

满足以下条件:

  1. 接受一个或多个函数作为输入
  2. 输出一个函数

高阶函数一般是那些函数型包含多于函数。在函数式编程中,返回另一个函数的高阶函数被称为Curry化的函数。

函数作为参数传递

将函数作为参数传递,我们就可以抽离以部分容易变化的业务逻辑,这样可以分离业务代码中变与不变的部分

回调函数:

将函数传进一个方法中,函数不会立即执行,等待出来结果之后在执行。

let func = function (callback){
if(n === 'owen'){
callback() //回调函数
}
}
function say (){
console.log('Hello Word')
}
func(say)

Array 对象常用的方法

[1,2,3,4].forEach(iteration)
function iteration(v){
console.log(v)
}

作为返回值输出

让函数继续返回一个可执行的函数,意味着运行过程是可延续的。

判断数据类型

let type = type =>{
return obj => Object.prototype.toString.call(obj) === `[object ${type}]`
}
let isArray = type('Array'),isString = type('String'),isNumber = type('Number'),isObject = type('Object'); // or
let Type = (function(){
let type = {},types = ['Object','Array','Number','String']
for (let val of types) {
(function(str){
type[`is${str}`] = (obj) => Object.prototype.toString.call( obj ) === `[object ${str}]`
}(val))
}
console.log(type)
return type
}())
Type.isNumber(2) // true

实现AOP(面向切片编程)

AOP 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

JAVA 语言中 AOP 将一些跟核心业务逻辑模块无关的功能抽离出来,通常包括日志统计、安全控制、异常处理灯。再通过“动态织入”的方式掺入业务逻辑中。

好处: 可以保持业务逻辑模块的纯净和高内聚,方便复用日志统计等功能模块。

JavaScript中实现AOP是指把一个函数“动态织入”到另一个函数之中

具体实现:

Function.prototype.before = function(beforeFn){
let that = this; // 谁调用指向谁 下面是由 func 函数调用所以是指向 func return function( ...args){
beforeFn.apply(this,args) // 执行回调函数 beforeFn
return that.apply(this,args) // 执行原函数
}
} Function.prototype.after = function(afterFn){
let that = this; // 谁调用指向谁 下面是由befor函数调用所以是指向 befor
return function( ...args){
let ret = that.apply(this,args) // 执行并接收原对象
afterFn.apply(this,args) // 执行回调函数 beforeFn
return ret
}
}
var func = function (){
console.log(2)
}
func = func.before(function (){
console.log(1)
}).after(function (){
console.log(3)
})
func()
// 1 2 3

函数柯里化 (function currying)

在数学和计算机科学中,柯里化是将多个参数的函数转换成一系列使用一个参数的函数,且返回接受余下的参数的新函数

curring 又称部分求值;一个 curring 函数首先会接收一些参数,该函数并不会立即求值,而是继续返回另外一个函数,而刚传入的参数会被保存在形成的闭包中,待函数真正需要求值的时候,之前的所以参数都会被一次性用于求值

简单示例:

function add(a,b) {
return a + b
}
add(1,2) // 3

接下来使用 currying 实现一个几天之内消费总和的函数

// 普通方法
var cost = (function() {
var args = [];
return function(){
if(!arguments.length){
let money = 0
for (let val of args ){
money += val;
}
return money
}else{
[].push.apply(args,arguments)
}
}
})()
cost(100);
cost(100);
cost(100);
cost(); // 300 // currying
/**
* 保存原函数参数返回到新函数中使用
*/ // func(100,100,100) //300
function count (...args){
let num = 0;
if(args.length>1){
for (let v of args){
num +=v
}
return num
}else{
return args[0]
}
} var curry = function(func){
let args = []
return function fn(...Args){
if (Args.length){
[].push.apply(args,Args)
return fn
}else{
return func.apply(this,args)
}
}
}
cost = curry(count); cost(100);
cost(100);
cost(100);
cost(); // 300

函数节流

JavaScript 中大多数情况都是用户主动出发函数,除非函数本身的实现不合理,否则一般不会遇到跟性能相关的问题,少数情况下,函数不是由用户直接触发控制,可能被频繁调用造成严重的性能问题。

比如:

window.addEventListener('resize', function(e) {
// do something...
});
window.addEventListener('scroll', function(e) {
// do something...
});
Dom.addEventListener('mousemove', function(e) {
// do something...
}); // progress
xhr.upload.addEventListener("progress", function(result) {
// do something...
}, false); // ...

上述事件1秒种触发很多次,并且常常操作DOM节点,非常损耗性能,浏览器会因此吃不消而卡顿;实际我们不需要触发如此高的频率因此我们可以在一段时间内忽略掉一些执行次数

节流原理:

如果持续触发事件,可每隔一段时间只执行一次。

使用定时器实现节流

将即将被执行的函数用 setTimeout 函数延迟一段时间执行,如果该定时器未执行完成则忽略接下下来的需被执行的函数。

 function throttle(func,wait) {
let timer, firstFlag = true; //第一次立即执行
return function(...args) {
let that = this;
if(firstFlag){
firstFlag = false;
return func.apply(that,args);
} if(timer) return false; // 如果存在定时器这不执行 timer = setTimeout(function(){
clearTimeout(timer);
timer = null;
func.apply(that,args);
},wait)
}
}
window.addEventListener('scroll', throttle(function() {
console.log(132)
},1000));

函数防抖

和节流一定时间段内只调用一次事件处理函数不同,防抖是一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。(用户不再触发对应事件才执行一次事件)

function debounce(func,wait) {
let timer;
return function(...args) {
let that = this;
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(that,args)
},wait)
}
}
window.addEventListener('scroll', debounce(function() {
console.log(123)
},1000));

个人博客

参考资料

《JavaScript设计模式与开发实践》

维基 AOP

维基 高阶函数

JavaScript专题之跟着 underscore 学节流

JavaScript高阶函数(Heigher-order function)的更多相关文章

  1. 高阶函数 - Higher Order Function

    一个函数如果有 参数是函数 或 返回值是函数,就称为高阶函数. 这篇文章介绍高阶函数的一个子集:输入 fn,输出 fn'. 按 fn 与 fn' 功能是否一致,即相同输入是否始终对应相同输出,把这类高 ...

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

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

  3. JavaScript高阶函数之filter、map、reduce

    JavaScript高阶函数 filter(过滤) 用法: 用于过滤,就是把数组中的每个元素,使用回调函数func进行校验,回调函数func返回一个布尔值,将返回值为 true 的元素放入新数组 参数 ...

  4. JavaScript高阶函数

    所谓高阶函数(higher-order function) 就是操作函数的函数,它接收一个或多个函数作为参数,并返回一个新函数. 下面的例子接收两个函数f()和g(),并返回一个新的函数用以计算f(g ...

  5. JavaScript高阶函数 map reduce filter sort

    本文是笔者在看廖雪峰老师JavaScript教程时的个人总结 高阶函数            一个函数就接收另一个函数作为参数,这种函数就称之为高阶函数          1.高阶函数之map:   ...

  6. JavaScript高阶函数的应用

    定义 高阶函数是指至少满足下列条件之一的函数: 函数可以作为参数被传递: 函数可以作为返回值输出. JavaScript语言中的函数显然满足高阶函数的条件,在实际开发中,无论是将函数当作参数传递,还是 ...

  7. JavaScript 高阶函数 + generator生成器

    map/reduce map()方法定义在JavaScript的Array中,我们调用Array的map()方法,传入我们自己的函数,就得到了一个新的Array作为结果: function pow(x ...

  8. JavaScript 高阶函数

    高阶函数的英文叫Higher-order function ,什么是高阶函数呢>? JavaScript的函数其实都指向某个变量.既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接 ...

  9. 浅析javascript高阶函数

    什么是高阶函数:在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数: 1. 接受一个或多个函数作为输入: 2. 输出一个函数.在数学中它们也叫做算子(运算符)或泛函.微积分中的导数就是常见的例 ...

随机推荐

  1. 【LiteOS】LiteOS移植常见问题

    发现很多人在LiteOS的移植过程中总会遇到一些问题,现在简单做一些总结.后续有新的问题提再继续补充. 1.CMSIS版本导致的问题 问题现象一般如下图所示,编译后报错,Undefined symbo ...

  2. 全面认识 RUST -- 掌控未来的雷电

    文章目录 RUST 简介 如何衡量语言的好坏? 静态语言 编译器 语言定位 代表性项目 Hello World RUST 前景 RUST 简介 Rust 是一种兼顾内存安全.高并发和稳定运行的编程语言 ...

  3. MAC vim修改hosts文件

    在终端输入sudo vim /etc/hosts 输入密码获取写权限 输入i,执行insert插入修改操作,修改hosts文件内容 修改完成后先按ESC进入命令模式,再按shift + :,在底端出现 ...

  4. 微信小程序 buton清除默认样式

    相信很多小伙伴在开发小程序的时候都会碰到小程序Button默认样式的困扰,在重设样式的时候需要一次次的设置 分享一个自己在开发中的小方法: CSS all 简写属性 将除 unicode-bidi 与 ...

  5. BX谷 2019年最新所有人都能学会的数据分析课视频教程

    第一章 数据分析师职业概览 1-1 数据分析师的职业概览免费试学 数据分析师的"钱"景如何 什么人适合学数据分析 数据分析师的临界知识 数据分析师的主要职责 第二章 数据分析和数据 ...

  6. k8s 开船记-修船:改 readinessProbe ,去 DaemonSet ,上 Autoscaler

    (图片来自网络) 改 readinessProbe 对于昨天 k8s 尼克号发生的触礁事故,我们分析下来主要是2个原因,一是当时4个节点不够用造成部分容器负载过高而宕机,二是 readinessPro ...

  7. python 2.7导入模块问题

    有如下结构的python文件 base |----pkg1 |----__init__.py |----add.py |----pkg2 |----__init__.py |----call_func ...

  8. java开发必学知识:动态代理

    目录 1. 引言 2. 代理模式及静态代理 2.1 代理模式说明 2.2 静态代理 2.3 静态代理局限性 3. 动态代理 3.1 JAVA反射机制 3.2 JDK动态代理 3.2.1 JDK动态代理 ...

  9. 一个简单的示例在spring boot中实现国际化

    最近在网上找了一个有关账单管理的spring boot项目,其中有一部分是涉及显示国际化信息的,即将页面上的中英文进行转换.因为在这之前这部分内容没有接触过,所以在这记录下过程. 中文效果图如下所示: ...

  10. NodeJS4-3静态资源服务器实战_优化成近似同步写法

    实例3 上面有点回调,优化成近似同步的写法 route.js const fs =require('fs') const promisify = require('util').promisify; ...