什么是函数式编程
函数式编程(Functional Programming, FP),FP 是编程范式之一,我们常听说的编程范式还有面向过程编程、面向对象编程。
面向对象编程的思维方式:把现实世界中的事物抽象成程序世界中的类和对象,通过封装、继承和多态来演示事物事件的联系。
函数式编程的思维方式:把现实世界的事物和事物之间的联系抽象到程序世界(对运算过程进行抽象)。
函数式编程中的函数指的不是程序中的函数(方法),而是数学中的函数即映射关系,例如:y
= sin(x),x和y的关系。
相同的输入始终要得到相同的输出(纯函数)。
函数式编程用来描述数据(函数)之间的映射。
高阶函数
可以把函数作为参数传递给另一个参数。
可以把函数作为另一个函数的返回结果
函数作为参数:此样例为用函数式编程来模拟高阶函数forEach和filter的实现。
// 高阶函数-函数作为参数
function forEach (array, fn) {
for (let i = 0; i < array.length; i++) {
fn(array[i])
}
}
// 测试
// let arr = [1, 3, 4, 7, 8]
// forEach(arr, function (item) {
// console.log(item)
// })
// filter
function filter (array, fn) {
let results = []
for (let i = 0; i < array.length; i++) {
if (fn(array[i])) {
results.push(array[i])
}
}
return results
}
// 测试
let arr = [1, 3, 4, 7, 8]
let r = filter(arr, function (item) {
return item % 2 === 0
})
console.log(r)
函数作为返回值:由于纯函数可缓存,故pay(5)只会执行一次
// 高阶函数-函数作为返回值
// function makeFn () {
// let msg = 'Hello function'
// return function () {
// console.log(msg)
// }
// }
// // const fn = makeFn()
// // fn()
// makeFn()()
// once
function once (fn) {
let done = false
return function () {
if (!done) {
done = true
return fn.apply(this, arguments)
}
}
}
let pay = once(function (money) {
console.log(`支付: ${money} RMB`)
})
pay(5)
pay(5)
pay(5)
pay(5)
常用的高阶函数:
- forEach
- map
- filter
- every
- some
- find/findeIndex
- reduce
- sort 等
接下来我们来模拟map、every、some的实现原理
// 模拟常用高阶函数:map、every、some
// map
const map = (array, fn) => {
let results = []
for (let value of array) {
results.push(fn(value))
}
return results
}
// 测试
// let arr = [1, 2, 3, 4]
// arr = map(arr, v => v * v)
// console.log(arr)
// every
const every = (array, fn) => {
let result = true
for (let value of array) {
result = fn(value)
if (!result) {
break
}
}
return result
}
// 测试
// let arr = [9, 12, 14]
// let r = every(arr, v => v > 10)
// console.log(r)
// some
const some = (array, fn) => {
let result = false
for (let value of array) {
result = fn(value)
if (result) {
break
}
}
return result
}
// 测试
let arr = [1, 3, 5, 9]
let r = some(arr, v => v % 2 === 0)
console.log(r)
闭包
闭包可以说是无处不在的,当我们还没听说这个概念的时候我们就可能已经在应用了。如果我们清楚堆栈的概念、理清了作用域,那么理解起来便不那么复杂。
函数和其周围的状态的引用捆绑在一起便形成闭包,简单来说就是可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员。
如下代码中便形成了简单的闭包。(调用fn()时执行了makeFn(),此时返回的匿名函数中又访问到了msg,故形成闭包)
// 简单闭包函数
function makeFn(){
let msg='Hello Prince'
return function(){
console.log(msg);
}
}
const fn =makeFn()
fn()
闭包总结:函数在执行的时候会放到一个执行栈上当函数执行完毕之后会从执行栈上移除,但是堆上的作用域成员因为被外部引用不能释放,因此内部函数依然可以访问外部函数的成员