一. 高阶函数的基本概念
- 把函数作参数或者返回值的一类函数
- 一个函数的参数是一个函数(回调函数就是一种高阶函数)
- 如果一个函数返回一个函数,当前这个函数也是一个高阶函数
二.AOP(面向切面编程)
- AOP主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,其实就是给原函数增加一层,不用管原函数内部实现
- 借助高阶函数实现一个封装,不改变当前公共逻辑
function say(a, b) {
console.log('say', a, b)
}
Function.prototype.before = function(callback) {
return function() {
callback();
this();
}
}
Function.prototype.before = function(callback) {
return (...args) => {
callback();
this(...args);
}
}
let beforeSay = say.before(function() {
console.log('before say');
})
beforeSay('hello', world);
三. 函数柯里化
- 柯里化,类似于函数,先确定一个参数,提取封装,改变另一个参数
- 柯里化就是把大的范围转成小的范围
1. 判断变量类型的四种方法
- typeof:不能判断对象类型
typeof[]和typeof{}的结果都是'object'
- constructor:可以找到这个变量是通过谁构造出来的
[].constructor => f Array(),({}).constructor => f Object()
- instanceof:判断是谁的实例(会有不准确的情况)
[1,2] instanceof Array === true
- Object.prototype.toString.call():对象原型提供的toString方法,不能区分是谁的实例
Object.prototype.toString.call('dddddd') ==> "[object String]"
2. 用柯里化实现一个判断类型的方法
2.1 高阶函数实现
function isType(type, value) {
return Object.prototype.toString.call(value) === `[object ${type}]`
}
console.log(isType('Array', [1, 2]));
function isType(type) {
return function(value) {
return Object.prototype.toString.call(value) === `[object ${type}]`;
}
}
let isArray = isType('Array');
console.log(isArray('hello'));
console.log(isArray([]));
2.2 柯里化实现
function sum(a, b, c, d, e, f) {
return a + b + c + d + e + f;
}
let r = currying(sum)(1, 2)(3, 4)(5)(6);
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 (concatValue.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(isArray('string'));
console.log(isArray([]));
四.高阶函数的应用
let fs = require('fs');
let school = {};
let index = 0;
const cb = () => {
if(++index === 2) {
console.log(school);
}
}
function after(times, callback) {
return function() {
if(--times === 0) {
callback();
}
}
}
let cb = after(2, function() {
console.log(school);
})
fs.readFile('./name.txt','utf8',function (err,data) {
school.name = data;
cb();
})
fs.readFile('./age.txt','utf8',function (err,data) {
school.age = data;
cb();
});
五.发布订阅&观察者模式
1.发布订阅
- 发布订阅模式分成两个部分:on(订阅),emit(发布)
- 订阅和发布没有明显的关联,靠中介
- on:订阅,把一些函数维护到一个数组中
- emit:发布,让数组中方法依次执行
let fs = require('fs');
let event = {
arr:[],
on(fn){
this.arr.push(fn);
},
emit(){
this.arr.forEach(fn=>fn());
}
}
event.on(function () {
console.log('读取了一个')
})
event.on(function () {
if(Object.keys(school).length === 2){
console.log('读取2个完毕', school)
}
})
let school = {}
fs.readFile('./name.txt','utf8',function (err,data) {
school.name = data;
event.emit();
});
fs.readFile('./age.txt','utf8',function (err,data) {
school.age = data;
event.emit();
});
2.观察者模式
class Subject {
constructor(name){
this.name = name;
this.state = '开心的';
this.observers = [];
}
attach(o){
this.observers.push(o);
}
setState(newState){
this.state = newState;
this.observers.forEach(o=>o.update(this))
}
}
class Observer{
constructor(name){
this.name = name
}
update(baby){
console.log('当前'+this.name +'被通知了','当前小宝宝的状态是'+baby.state)
}
}
let baby = new Subject('小宝宝');
let parent = new Observer('爸爸');
let mother = new Observer('妈妈');
baby.attach(parent);
baby.attach(mother);
baby.setState('被欺负了');