1.什么是高阶函数
在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:
- 接受一个或多个函数作为输入
- 输出一个函数
利用高阶函数可以解决什么问题
- 扩展方法
如:
function say (args) { // 我们需要对say方法进行扩展,但是不能修改源码
console.log('say', args)
}
Function.prototype.before = function (cb) {
return (...args) => { // newSay
cb()
this(...args) // 扩展原来的函数
}
}
let newSay = say.before(() => {
console.log('before')
})
newSay('hello')
// 输出
// before
// say hello
我们可以通过高阶函数来实现参数的保留
示例:
比如我们可以实现判断值的类型
一般判断数据类型有以下方法
- typeof 一般用于判断基本类型
- instanceof xxx是谁的实例,原理
- Object.prototype.toString.call 判断具体类型,返回的是一个字符串
- constructor可以看当前实例是由谁构造出来的, 深拷贝
我们先定义一个通用的判定函数
function isType(val, typing) {
return Object.prototype.toString.call(val) === `[object ${typing}]`
}
那么我们判断一个值是否为字符串可以这样写
console.log(isType('hello', 'String')) // true
console.log(isType(456, 'String')) // false
那么我们能不能定义isString
,isNumber
函数,不需要用户手动传入 String
,Number
字段呢?当然可以,下面改造isType函数
function isType (typing) {
return (val) => {
return Object.prototype.toString.call(val) === `[object ${typing}]`
}
}
// 比较函数声明的作用域和执行的作用域不一样的,这时候就会形成闭包
let isString = isType('String')
console.log(isString('123')) // true
console.log(isString(123)) // false
利用高阶函数保留参数,进一步可以实现函数的柯里化和函数的反柯里化
2.什么是柯里化
柯里化(currying)指的是将一个多参数的函数拆分成一系列函数,每个拆分后的函数都只接受一个参数(unary)。
下面我们尝试实现通用的柯里化参数,也是一个高阶函数
function sum (a, b, c, d) {
return a + b + c + d
}
sum(1, 2, 3, 4) // 10
上面代码中,函数sum
接受四个参数a
、b
、c
和d
。
柯里化就是将上面的函数拆分成四个函数,每个函数都只接受一个参数。
function curring (fn) {
// 存储每次调用的时候传入的变量
const inner = (args = []) => {
return args.length >= fn.length ? fn(...args) : (...userArgs) => inner([...args, ...userArgs])// 递归返回函数
}
return inner()
}
let sum1 = curring(sum)
let sum2 = sum1(1)
let sum3 = sum2(2, 3)
let result = sum3(4)
console.log(sum4)
然后再来看我们的类型判断函数
let isString = curring(isType)('String')
console.log(isString('abc')) // true
let isNumber = curring(isType)('Number')
console.log(isNumber(123)) // true
如果有很多很多判断变量的方法,我们可以整合一下
let util = {};
['String', 'Number', 'Boolean', 'Null', 'Undefined'].forEach(type => {
util[`is${type}`] = curring(isType)(type)
});
console.log(util.isString(123)) // false
console.log(util.isString('123')) // true
console.log(util.isNumber(123)) // true
console.log(util.isBoolean(123)) // false
console.log(util.isBoolean(true)) // true
console.log(util.isNull(null)) // true
console.log(util.isNull(123)) // false
console.log(util.isUndefined(undefined)) // true
console.log(util.isUndefined(null)) // false
我们用3行代码就实现了几乎JavaScript的所有数据类型判断,是不是很厉害!