在学习前端的时候,我老是能听到不少高级词汇,好比今天会聊到的 函数式编程(Functional Programming) & 高阶函数 (Higher-order function) 。 可是当你真正的理解什么是 函数式编程 & 高阶函数 的时候,也许会发现,你几乎天天都会用到它,只是你不知道那就是高阶函数 / 函数式编程。javascript
在 javascript
中,函数是一种值,举个例子:css
const double = function (x) {
return x * 2
}
复制代码
咱们把一个函数做为值,赋给了变量 double
,这在咱们的代码中很常见对吗?html
你是否是常常会听到或者看到这样一句话:“在 JavaScript 中函数是一等公民”前端
粗看很很差理解,可是它的意思很简单:函数和 字符串/number
没有什么不同,它能够声明为变量,也能够做为参数传入到其余函数中。vue
什么是高阶函数?其实上一段咱们已经说过了,咱们能够把函数A做为参数传入到另外一个函数B中,那么接收函数做为参数的函数B,就是 高阶函数 ,这只是方便你们理解,高阶函数的定义是:java
"一个函数的参数是另外一个函数,或者一个函数的返回值是另外一个函数"react
说到 filter()
你确定不陌生,他接收一个回调函数做为它的参数,因此它是一个典型的高阶函数,举个例子:git
咱们有这么一个数组,要筛选出对应 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 | 数组 => 大数组/小数组/单个元素/长度相等的数组/字符串/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()
复制代码
上节的这段代码
chainObj.double().add3().add3().add3().add3().getValue()
复制代码
对比 Promise 的代码
promise.then(fn).then(fn)...
复制代码
是否是很像呢?是的没错,咱们平时写的 promise
其实都是在处理咱们的 高阶函数 的执行顺序。
那么 Promise
又是如何实现这样的链式调用的呢?期待之后和你们分享~
小册 你不知道的 Chrome 调试技巧 已经开始预售啦。
欢迎关注公众号 「前端恶霸」,扫码关注,会有不少好东西等着你~