高阶函数是JavaScript进阶路上经常提到的问题。首先给出高阶函数的定义(参考MDN)。一个返回另外一个函数的函数被称为高阶函数。函数作为参数(回调函数),这里也认为是高阶函数。
返回一个函数
借助返回函数,生成了判断多个变量类型的函数。类似checkType 作为一个函数生成器有广泛的用途。
函数作为参数
函数作为参数,执行回调功能在JavaScript中应用非常广泛。使用回调可以解耦逻辑。
高阶函数之 函数回调地狱
有这样一个场景:
1. 调用 getUserInfo 接口,返回用户信息 userInfo
2. 传参 userInfo.id,调用 getTweetList 接口,返回用户状态列表:tweetList
3. 传参 tweet.id,调用getComments 接口,返回用户状态评论
// 使用上面定义的request方法request( {url: 'getUserInfo'}, userInfo => { const { id } = userInfo; request({ url: 'getTweetList', body: id}, (tweetList = []) => { const { id } = tweetList[0]; request({ url: 'getComments', body: id }, comments => { console.log(comments); }) })})
在复杂场景下回调函数会产生“回调地狱”的问题。幸好,现在已经有了成熟的解决方案:Promise、Async、Await
回调解决之Promise、Async、Await
async function getComments() { const { id } = await request({ url: 'getUserInfo' }); const [tweet] = await request({ url: 'getTweetList', body: id }); const comments = await request({ url: 'getComments', body: tweet.id }); return comments;}
tip: async function 返回是Promise。
基于 Promise、Async、Await 的写法逻辑清晰。对 Promise、Async、Await 的深入讲解就不在这里展开了。
高阶函数之 JavaScript常用方法
[3, 1, 2].sort((a, b) => a - b)// 输出:[1, 2, 3][3, 1, 2].findIndex(v => v === 3)// 输出:0[1,2,3].reduce((a, b) => a + b)// 输出:6[1,2,3].map(v => v * v)// 输出:[1, 4, 9][1,2,3].forEach(v => console.log(v))// 输出:1,2,3[1,2,3].filter(v => v > 1)// 输出:[2, 3]['String', 'Number', 'Object', 'Array', 'Function', 'AsyncFunction', 'Promise'].forEach(v => { window[`is${v}`] = checkType(v);})
tip:forEach 和 map的区别是,map会返回一个新的数组对象,而forEach不会。
高阶函数之观察者模式:Don't call me, I will call you.
观察者模式在JavaScript中使用非常广泛。页面加载事件,dom事件,mp3、video播放,canvas处理,js、css资源加载。Nodejs整个是架构在观察者模式上的(大部分core module 都继承了events module)。
观察者模式的简单实现
// 观察者模式使用const eventcenter = new EventCenter();eventcenter.on('time-update', time => { console.log(time); });const id = setInterval(() => { eventcenter.emit('time-update', Date.now()); }, 1000);// 停止事件触发setTimeout(() => { clearInterval(id);});
观察者模式的优势是,逻辑解耦。在设计自己的代码时,可以考虑使用观察者模式进行代码分离。比如设计 http 请求的 request 方法类似jQuery的ajax。
// 使用 Request 对象const request = new Request();request.on('success', resp => { console.log(resp);}).on('error', error => { console.log(error);});request.get({ url: 'request url' });
Request对象继承了EventCenter,拥有了注册、触发事件的能力。成功和失败的回调通过事件注册,进行了解耦。
高阶函数之 Redux Middlewares
const logMiddleware = store => next => action => { // process business next(action);}
middleware中每层的 next 是不相同的。观察下下面的方法。
function showLog() { console.log('showLog');}function enhanceFn(fn) { return function () { console.log('log before'); fn(); console.log('log after'); }}showLog = enhanceFn(showLog);// 输出:// log before// showLog// log after
当对 store.dispatch 反复使用类似的逻辑(compose方法),可以产生middleware的效果。
高阶函数之 JavaScript AOP
JavaScript AOP指将一个函数动态织入另一个函数中。
showLog = enhanceFn(showLog);// 输出:// log before// showLog// log after
动态织入,上面的 enhanceFn 函数也可以实现。vue的实现原理将另一种动态织入的方式让大家熟知。
ES6 里面有了新的解决方案,Proxy 和 Reflex。
const obj = {};const proxy = new Proxy(obj, { get: function (target, key, receiver) { return Reflect.get(target, key, receiver); }, set: function (target, key, value, receiver) { // 执行变更 Reflect.set(target, key, value, receiver); // 触发变更事件 eventCenter.emit("time-update", value); return true; } }); // 使用 const timerId = setInterval(() => { proxy.time = Date.now(); }, 1000); setTimeout(() => clearInterval(timerId), 1000 * 10);
高阶函数的应用介绍到这里了,希望对大家有所帮助。欢迎大佬转发支持,提出宝贵意见。