高阶函数
定义: 参数或者返回值是函数的函数 如:回调函数
- before
扩展当前已有功能
// 原有方法
function say(a, b) {
console.log('say', a, b)
}
// before 该方法会在函数调用前调用
Function.prototype.before = function (callBack) { // 函数原型链
return (...args) => { // ...args 剩余运算符 箭头函数没有this,没有arguments
callBack()
this(...args) // 展开运算符
}
}
// 自定义的beforeSay
let beforeSay = say.before(function () {
console.log('beforesay...')
})
beforeSay('j', 's')
-函数柯里化 /函数反柯里化
-
判断类型的4中方法
- typeof 不能判断对象类型
- constructor 可以找到这个变量是通过谁构造出来的
- instantceof 判断谁是谁的实例
- Object.prototype.toString.call() 缺陷是不能细分谁是谁的实例
//demo 判断类型 function isType(type,value){ return Object.prototype.toString.call(value)===`[object ${type}]` } isType('Array',[]) // 缺陷 ,需要用户输入类型字符串,易出错; 如果可以直接isArray(),isString()就好啦
// 简单柯里化 (先固定了某些参数)
function isType(type, value) {
return (value) => {
return Object.prototype.toString.call(value) === `[object ${type}]`
}
}
let isArray = isType('Array')
isArray([])
// 通用柯里化函数
// 原函数
function isType(type,value){
return Object.prototype.toString.call(value)===`[object ${type}]`
}
// 柯里化
const currying = (fn, arr = []) => {
let len = fn.length // 函数参数的长度
return function (...args) {
let concatValue = [...arr, ...args]
if (arr.length < len) {
return currying(fn, concatValue)
} else {
return fn(...concatValue)
}
}
}
// 使用
let isArray = currying(isType)('Array')
let isString = currying(isType)('String')
console.log(isArray([]))
console.log(isString('123'))
-after
闭包:函数定义的作用域和执行的作用域不同
- 返回内部函数,内部函数引用外部函数参数
// 案例 多个异步函数,在异步函数结束后执行某个操作
function after(times, callBack) { // 闭包函数
return function () {
if (--times === 0) {
callBack()
}
}
}
let cb = after(2, () => { // 灵活可变
console.log('调用完成')
})
setTimeout(function () { // 异步操作
console.log(1, cb.toString())
cb()
}, 200);
setTimeout(() => { // 异步操作
console.log(2)
cb()
}, 0);
发布订阅模式 on-emit
// on-emit 需要中介 发布和订阅没有直接关系, 可以只发布不订阅,也可以只订阅不发布
const event = {
arr: [],
times: 0,
on: function (fn) {
// console.log('on', this) // 普通函数里this指向当前对象
this.arr.push(fn)
},
// error: () => {
// console.log('error', this) // 箭头函数里 window
// },
emit() {
this.times++
this.arr.forEach(e => e());
}
}
event.on(() => {
console.log('订阅事件')
})
event.on(() => {
if (event.times === 2) {
console.log('执行结束')
}
})
setTimeout(function () {
event.emit() // 触发
}, 200);
setTimeout(() => {
event.emit()
}, 0);
观察着模式
- 观察者放到被观察者里,被观察者一旦发生改变,观察者执行事件;两者强关联
// 观察着模式 发布和订阅都在被观察对象里
class Subject {
constructor(name) {
this.name = name;
this.state = '开心';
this.observers = []
}
attact(o) { // 添加观察者
this.observers.push(o)
}
setState(s) {
this.state = s
this.observers.forEach(i => i.update(this))
}
}
class observer {
constructor(name) {
this.name = name
}
update(s) {
console.log(this.name + '被通知' + s.state)
}
}
let baby = new Subject('小宝宝')
let papa = new observer('papa')
let mama = new observer('mama')
baby.attact(papa)
baby.attact(mama)
baby.setState('难过')
baby.setState('饿了')