高阶函数
1、参数是一个函数
2、函数返回值是一个函数
满足其中一点 就被称为高阶函数
函数的before
意思就是在执行一个函数之前先执行某函数。
//比如我们要吃饭,创建一个吃饭的方法
function eat() {
console.log('吃饭')
}
//吃饭之前呢我们需要做饭,再创建一个做饭的方法
function cooking() {
console.log("做饭")
}
// 通常我们这样就行了
// function eat() {
// cooking()
// console.log('吃饭')
// }
// eat()
// 这样实现没毛病可以做到,不过这样耦合性太高了,万一不想做饭想叫外卖吃个烤鸭呢?
function takeaway(){
console.log("叫外卖吃烤鸭!")
}
// 我们需要修改eat方法,内置takeaway进去
// 所以我们需要改变思路创建一个before的功能例如:
// eat.before("cooking") //吃饭前先做饭
// eat.before("takeaway") //吃饭前叫一个烤鸭外卖
// 。。。等等操作
// 具体怎么做呢?
// 预想的before很明显是eat的一个方法,那么我们就能知道before需要挂载到函数的原型上
Function.prototype.before = function(something){
something() //执行吃饭前做的一些事
this() //这里的this是吃饭,函数内部的this取决于函数的调用
}
// 试一下
eat.before(cooking)
eat.before(takeaway)

// 不过这样还是有一点问题,比如吃饭的时候(晚饭来点啤酒),这样怎么加呢
//希望结果是 叫烤鸭外卖,吃饭的时候来点啤酒
// let dinner = eat.before(takeaway);
// dinner("配点啤酒")
// eat.before(takeaway) //返回一个可执行的方法还得能支持特殊要求,过分吗过分 不过我们还是可以满足的
Function.prototype.before = function (something) {
// 返回一个函数
return (...arg)=>{ //为了满足各种需求,参数我们用...arg (剩余所有参数以数组的形式传进去)
// console.log(...arg) //到了里边再展开
something() //饭前不管是做饭还是叫外卖这个得先做了
this(...arg) //吃饭同样很重要,接下来就是怎么满足特殊需求了,啤酒 红酒 白酒 鸡尾酒啥的
}
}
let dinner = eat.before(takeaway);
dinner("配点啤酒","再来点白酒")
// 改造下eat方法
function eat(...arg){ //同样把参数以数组的形式放进去(我们不知道有多少种酒能满足)
let claim = ""
arg.map(item=>{
claim+=item
})
console.log(claim)
}

类型判断封装
// 目前最好的办法是用 Object.prototype.toString.call()
//例如
console.log(Object.prototype.toString.call('123')) //[object String]
// 我们如果想做一个通用方法
// checkType('123') //能得到正确的结果 需要怎么做呢
//通常我们这么做
function isType(obj){
return Object.prototype.toString.call(obj).slice(8,-1)
}
console.log(isType(123)) //Number 没问题
//不过我们是封装 ,我们想直接返回Boolean
// 这样改
// function checkType(obj,type){
// console.log(Object.prototype.toString.call(obj))
// return Object.prototype.toString.call(obj) === `[object ${type}]`
// }
// 测试
console.log(checkType(123,"Number")) //true 没问题 不过我们不满足,我们既然是封装 肯定是使用者怎么简单怎么来。
// 于是我们想是不是可以这样 isNumber()、isString().... 这样还能防止使用者 写错参数 例如类型全写小写了 等等
//还想使用者尽量少的传入参数,毕竟 类型是固定的
let types = ['String','Number','Object','Array','Function','Boolean']
let typeUtil = {}
// 既然我们只需要传入一个参数,那么type是需要内置的
// 需要改造checkType函数
function checkType(type){
return (obj)=>{
return Object.prototype.toString.call(obj) === `[object ${type}]`
}
}
types.forEach((type)=>{
typeUtil[`is${type}`] = checkType(type)
})
console.log(typeUtil.isNumber(123))
柯里化
// 柯里化
const add = (a,b,c,d)=>{
return a+b+c+d
}
const curry = (fn,arr=[])=>{
let len = fn.length
return (...arg)=>{
//累加参数 拿参数数组的长度和参数函数的长度做比较
arr = arr.concat(arg)
//如果参数不够 继续执行curry
if(arr.length<len){
return curry(fn,arr)
}
// 如果参数够了直接执行参数函数
return fn(...arr)
}
}
let curry1 = curry(add)
console.log(curry1(2)(3,4)(5))
更详细柯里化的请移步:https://segmentfault.com/a/1190000017998127
函数的after
//after 意思是执行一定次数后执行一个方法,例如下边函数 执行count次后再执行fn函数
function after(count,fn){
return ()=>{
//这里说说 count-- 和 --count 很好解释 减号在前边就会立刻执行减一操作 在后边 下次才会执行
if(--count === 0){
fn()
}
}
}
function callBack(){
console.log("两次一会执行结果")
}
let countAfter = after(2,callBack)
countAfter()
countAfter() //执行两次以后执行结果
// *实现解析 利用闭包的原理 存储count数 每执行一次做一次减减* 完成条件执行函数
网友评论