摘要:前言在学习前端的时候,我总是能听到很多高级词汇,比如今天会聊到的函数式编程高阶函数。接下来我们看看,高阶函数有可能会遇到的问题,又如何去解决。
前言
在学习前端的时候,我总是能听到很多高级词汇,比如今天会聊到的 函数式编程(Functional Programming) & 高阶函数 (Higher-order function) 。
但是当你真正的理解什么是 函数式编程 & 高阶函数 的时候,也许会发现,你几乎每天都会用到它,只是你不知道那就是高阶函数 / 函数式编程。
在 javascript 中,函数是一种值,举个例子:
const double = function (x) { return x * 2 }
我们把一个函数作为值,赋给了变量 double ,这在我们的代码中很常见对吗?
你是不是经常会听到或者看到这样一句话:“在 JavaScript 中函数是一等公民”
粗看很不好理解,但是它的意思很简单:函数和 字符串/number 没有什么不一样,它可以声明为变量,也可以作为参数传入到其他函数中。
什么是高阶函数?什么是高阶函数?其实上一段我们已经说过了,我们可以把函数A作为参数传入到另一个函数B中,那么接收函数作为参数的函数B,就是 高阶函数 ,这只是方便大家理解,高阶函数的定义是:
"一个函数的参数是另一个函数,或者一个函数的返回值是另一个函数"
高阶函数的例子 filter说到 filter() 你肯定不陌生,他接收一个回调函数作为它的参数,所以它是一个典型的高阶函数,举个例子:
我们有这么一个数组,要筛选出对应 category 为 html&css 的书籍。
const books = [ {name:"gitbook",category:"git"}, {name:"reactbook",category:"react"}, {name:"vuebook",category:"vue"}, {name:"cssbook",category:"html&css"}, {name:"htmlbook",category:"html&css"}, ]
传统的写法是这样:
let html_css_books = [] for (let i = 0; i < books.length; i++) { if(books[i].category === "html&css"){ html_css_books.push(books[i]) } } console.log(html_css_books)
我相信几乎没有人会选择上面的方式,大部分人都会用 filter
const html_css_books = books.filter(function(item){return item.category === "html&css"})
当然我们还可以用箭头函数来缩减一些代码:
const html_css_books = books.filter(item => item.category === "html&css")
我知道这是一个大家都明白的例子,从这里你能看到几个高阶函数的好处?
更短的代码
更少的错误
更多的复用
第三点你可能不同意,因为你可能会说,我们没有复用任何代码啊?但如果我们把传入的filter的回调函数抽离出来呢?因为真正决定要过滤哪些数据的是这个部分。
const is_html_css_books = item => item.category === "html&css" const is_git_books = item => item.category === "git" const is_not_git_books = item => item.category !== "git" const html_css_books = books.filter(is_html_css_books) const git_books = books.filter(is_git_books) const not_git_books = books.filter(is_not_git_books)
清晰又简洁不是吗?
filter & map & find & reduce这些都是我们常见的高阶函数,但是它们的用法各不相同
函数 | 返回值 |
---|---|
filter | 大数组 => 小数组 |
map | 数组 => 长度相等的数组 |
find | 数组 => 单个元素 |
reduce | 数组 => 大数组/小数组/单个元素/长度相等的数组/字符串/Number/其他值 |
reduce 有很多玩法,甚至它可以取代我们刚刚说的三种高阶函数,下一篇我们会聊聊 reduce 的内容。接下来我们看看,高阶函数有可能会遇到的问题,又如何去解决。
问题 & 解决 问题我们一起来看这样一个场景
比如我们需要计算 a, b 两个值的和的两倍再加3,我们可能会定义两个函数
function double(a, b) { return (a + b) * 2 } function add3(a) { return a + 3 }
那么我们会这样调用:
add3(double(1,3))
但是如果我们需要多加几次3呢?
add3(add3(add3(add3(add3(double(1,3))))))
是的,虽然计算没有错误,但是我们的可读性大大降低了,那面对这样的情况如何处理呢?
解决:链式优化解决嵌套的第一种方法,就是拆解嵌套,链式调用,就像一条链子一样,一环套一环,将上次的结果,作为下次的参数。
const chainObj = { double(a,b) { this.temp = (a + b) * 2; return this; }, add3() { this.temp += 3; return this; }, getValue() { const value = this.temp; // 记得这里要初始化temp值 this.temp = undefined; return value; } };
所以我们上面的嵌套现在可以这样写:
chainObj.double().add3().add3().add3().add3().getValue()Promise
上节的这段代码
chainObj.double().add3().add3().add3().add3().getValue()
对比 Promise 的代码
promise.then(fn).then(fn)...
是不是很像呢?是的没错,我们平时写的 promise 其实都是在处理我们的 高阶函数 的执行顺序。
那么 Promise 又是如何实现这样的链式调用的呢?下一次和大家分享~
最后这里是 Dendoink
奇舞周刊原创作者
掘金 [联合编辑 / 小册作者]
segmentfault [漫谈前端 / 系列作者]
公众号 [前端恶霸 / 主笔]
对于技术人而言:技 是单兵作战能力,术 则是运用能力的方法。得心应手,出神入化就是 艺 。在前端娱乐圈,我想成为一名出色的人民艺术家。
扫码关注公众号 前端恶霸 我在这里等你:
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/104395.html
摘要:数据的层级意味着迭代数据结构并提取它的数据。对于技术人而言技是单兵作战能力,术则是运用能力的方法。在前端娱乐圈,我想成为一名出色的人民艺术家。 聊聊 for of 说起 for of 相信每个写过 JavaScript 的人都用过 for of ,平时我们用它做什么呢?大多数情况应该就是遍历数组了,当然,更多时候,我们也会用 map() 或者 filer() 来遍历一个数组。 但是就...
摘要:你能学到什么如何使用实现异步编程异步编程的原理解析前言结合上一篇文章,我们来聊聊基础原理说到异步编程,你想到的是和,但那也只是的语法糖而已。表示一个异步操作的最终状态完成或失败,以及其返回的值。至此实现异步操作的控制。 你能学到什么 如何使用 Generator + Promise 实现异步编程 异步编程的原理解析 前言 结合 上一篇文章 ,我们来聊聊 Generator 基础原理...
摘要:能帮我们解决什么痛点实现异步执行,在未出现前,我们通常是使用嵌套的回调函数来解决的。那么,接下来我们看一下使用的实例可以传入两个参数表示两个状态的回调函数,第一个是,必选参数第二个是,可选参数的方便之处。 深入理解promise 对于现在的前端同学来说你不同promise你都不好意思出门了。对于前端同学来说promise已经成为了我们的必备技能。 那么,下面我们就来说一说promise...
阅读 847·2021-11-25 09:43
阅读 3680·2021-11-19 09:40
阅读 881·2021-09-29 09:34
阅读 1782·2021-09-26 10:21
阅读 870·2021-09-22 15:24
阅读 4187·2021-09-22 15:08
阅读 3265·2021-09-07 09:58
阅读 2654·2019-08-30 15:55