函数式编程是一个非常古老的概念, 早于第一台计算机的诞生
为什么现在还要学习函数式编程?
函数式编程(英语:functional programming)或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免>使用程序状态以及易变对象。函数编程语言最重要的基础是λ演算(lambda calculus)。而且λ演算的函数可以接受函数当作输入和输出。 历史函数式编程中最古老的例子莫过于1958年被创造出来的LISP了。但是要提及函数式编程的例子却不得不从更早的λ演算说起。
计算两个数的和
在我们初学编程的时候会先定义两个数,然后把这两个数相加,用一个变量保存,这种方式是非函数式的,是通过步骤一步一步做出来的,这是面向过程的编程方式
// 非函数式
let num1 = 1
let num2 = 2
let sum = num1 + num2
console.log(sum)
如果我们使用函数式编程,需要把运算过程进行抽象,首先我们需要抽象一个 add 的函数,这个函数需要接收两个参数,当这个函数执行完的时候需要把两个值的计算结果返回,所以函数式编程中的函数一定要有输入,一定要有输出,并且相同的输入要有相同的输出
, add 函数定义完成之后,我们就可以调用add函数传对饮的参数并把结果保存起来
// 函数式
function add (n1, n2) {
return n1 + n2
}
let sum = add(1, 2)
console.log(sum)
当使用函数式编程的时候一定会有一些函数,这些函数可以无数次的重用,所以函数式编程的好处就是可以让代码进行重用,这些函数可以组合成功能更强大的函数
函数是一等公民(英文:First-class citizen) JavaScript 语言将函数看作一种值,与其它值(数值、字符串、布尔值等等)地位相同。凡是可以使用值的地方,就能使用函数。比如,可以把函数赋值给变量和对象的属性,也可以当作参数传入其他函数,或者作为函数的结果返回。函数只是一个可以执行的值,此外并无特殊之处。由于函数与其他数据类型地位平等,所以在 JavaScript 语言中又称函数为 第一等公民。
// 赋值给变量
let fn = function () {
console.log('First-class citizen')
}
let Dialog = {
show () {
return View.show()
},
hide () {
return View.hide()
}
}
// 与上面等价
let Dialog = {
show: View.show,
hide: View.hide,
}
function alert () {
console.log('alert')
}
function trigger (callback) {
typeof callback === 'function' && callback()
}
// 函数作为参数
trigger(alert)
function add (n1, n2) {
let sum = n1 + n2
return function (n3) {
return sum + n3
}
}
let fn = add(1, 2)
let num = fn(3)
用函数的特性模拟数组方法
实现forEach
forEach() 方法对数组的每个元素执行一次提供的函数。
function forEach (array, fn) {
for (let i=0; i<array.length; i++) {
fn(array[i], i, array)
}
}
// 测试
let arr = [1, 2, 3]
forEach(arr, (item) => {
console.log(item)
})
实现filter
filter用于对数组进行过滤。它创建一个新数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
function filter (array, fn) {
let results = []
for (let i=0; i<array.length; i++) {
if (fn(array[i], i, arr)) {
results.push(array[i])
}
}
return results
}
// 测试
let arr = [1, 2, 3, 4, 5]
let newArray = filter(arr, (item) => {
return item > 2
})
实现once函数
在实际的工作中我们可能经常遇到某些内容只执行一次,不再需要执行,我们可以把这些内容封装成函数,作为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} 元`)
})
// 多次执行只会执行一次
pay(2)
pay(2)
pay(2)
pay(2)
pay(2)
实现map方法
方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成
function map (array, fn) {
let results = []
for (let i=0; i<array.length; i++) {
results.push(fn(array[i]))
}
return results
}
// 测试
let arr = [1, 2, 3, 4]
let newArray = map(arr, (item) => {
return item * 2
})
实现every方法
方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值
function every (array, fn) {
let result = true
for (let i = 0; i < array.length; i++) {
if(!fn(array[i], i, array)){
result = false
break;
}
}
return result
}
// 测试
let arr = [4, 5, 6]
console.log(every(arr, (item) => {
return item > 3
}))
实现some方法
方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean 类型的值。
function some (array, fn) {
let result = false
for (let i = 0; i < array.length; i++) {
if(fn(array[i], i, array)){
result = true
break;
}
}
return result
}
// 测试
let arr = [4, 5, 6]
console.log(some(arr, (item) => {
return item > 3
}))
使用高阶函数的意义