函数类型(高阶函数)
Opened this issue · 0 comments
adodo0829 commented
函数类型(高阶函数)
函数操作函数 => 就是高阶函数; 函数有时候我们理解为一系列规则的集合, 指令集.
# 通常为两种情况
1.函数作为参数
2.函数作为返回值
函数作为参数的场景
- 回调函数callback
当把函数当作参数传递时, 我们可以抽离出一部分容易变化的业务逻辑(规则),
把这部分业务逻辑放在函数参数中, 这样一来可以分离业务代码中变化与不变的部分,
做到规则的抽象与分离.
doSomething(cb) {
// do something...
// 不变的业务逻辑
// then
// 可变的业务逻辑, 可支持自定义
cb()
}
# 典型的有 ajax 回调, 事件操作等
函数作为返回值的场景
- 抽离重复功能
当把函数当返回值输出时, 意味着我们可以延续上一步的运算;
这样我们可以抽离出重复的的业务逻辑(规则), 做到简化代码的作用
let isString = function(obj) {
return Object.prototype.toString.call(obj) === '[object String]';
};
let isArray = function( obj ){
return Object.prototype.toString.call(obj) === '[object Array]';
};
let isNumber = function( obj ){
return Object.prototype.toString.call(obj) === '[object Number]';
};
// 这些函数都有相同的部分, 那就是最后都调用Object.prototype.toString.call( obj )
// 我们抽离一下
let isType = function(type){
return function(obj){
return Object.prototype.toString.call(obj) === '[object '+ type +']';
}
};
// 之后你可以isType('你想要的判断类型的规则')
高阶函数应用
对于 js 这类语言来说, 我其实比较喜欢且倾向函数式编程, 奈何功底有限,还是得慢慢修炼
AOP(面向切面编程)
把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等。把这些功能抽离出来之后,再通过“动态织入”的方式掺入业务逻辑模块中。这样做的好处首先是可以保持业务逻辑模块的纯净和高内聚性,其次是可以很方便地复用日志统计等功能模块
在js中实现AOP,都是指把一个函数“动态织入”到另外一个函数之中
Function.prototype.before = function (beforefn) {
var _this = this; // 保存原函数的引用
return function () { // 返回包含了原函数和新函数的"代理"函数
beforefn.apply(this, arguments); // 先执行新函数,修正this
return _this.apply(this, arguments); // 再执行原函数
}
};
Function.prototype.after = function (afterfn) {
var _this = this;
return function () {
var ret = _this.apply(this, arguments); //先执行原函数
afterfn.apply(this, arguments); //再执行新函数
return ret;
}
};
var func = function () {
console.log(2);
};
func = func.before(function () {
console.log(1);
}).after(function () {
console.log(3);
});
func(); // 1, 2, 3
# 把负责打印数字1和打印数字3的两个函数通过AOP的方式动态植入func函数
一些工具函数
- 映射函数:返回的新函数将一个数组映射到另一个使用这个函数的数组上
function mapFunc(fn) {
return function(arr) {
return Array.prototype.map.call(arr, fn)
}
}
let increase = item => item + 1
let increaseMap = mapFunc(increase)
let a = [1,2,3]
increaseMap(a) // [2,3,4]
函数柯里化(currying)
currying又称部分求值函数。一个currying的函数首先会接受一些参数
,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数(单个参数)
,刚才传入的参数在函数形成的闭包
中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性
用于求值.
其主要用途在于参数复用。本质上是降低通用性,提高适用性。
- 计算一周的消费,只需要在周末求和
# 理解: 每天调用该函数,保存累计值,最后一次调用时,求和输出; 我们可以判断参数
let everyWeekCost = (function() {
// 闭包中用于保存数据的变量,本周每天的费用
var feeArgs = []
return function() {
// 此函数才是最终执行的函数
if (arguments.length === 0) {
return feeArgs.reduce((prev, curr) => {
return prev + curr
}, 0)
} else {
Array.prototype.push.apply(feeArgs, arguments)
}
}
})()
everyWeekCost(1)
everyWeekCost(2)
everyWeekCost(3)
...
everyWeekCost(7)
everyWeekCost() // 1 + 2 + 3...+ 7的结果
- 实现 add(1)(2)(3)() ==> 6
# 只要传了参数,就返回一个函数,并保存参数, 没有参数了就返回和值
function curryAdd() {
let argsList = []
// 返回一个闭包
let closure = function () {
// 本次调用传入的参数
let args = [...arguments]
if (args.length > 0) {
// 保存参数
argsList = argsList.concat(args)
// 再次返回闭包,等待下次调用
return closure
}
// 没有传递参数,执行累加
return argsList.reduce((prev, cur) => prev + cur)
}
return closure
}
let add = curryAdd()
console.log(add(1)(2)(3)())
# 还有一种是利用函数对象的 toString 方法