进阶学习1:函数式编程FP——概念头等函数高阶函数常用高阶函数模拟
Posted JIZQAQ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进阶学习1:函数式编程FP——概念头等函数高阶函数常用高阶函数模拟相关的知识,希望对你有一定的参考价值。
目录
1.面向过程编程Procedure Oriented Programming(POP):
2.面向对象编程Object Oriented Programming(OOP):
3.函数式编程Functional Programming(FP):
二、函数是一等公民 First-class Function(头等函数)
2.高阶函数 (Higher-order function)
一、函数式编程概念
函数式编程Functional Programming(FP),是编程范式之一,其他编程范式还有面向过程编程、面向对象编程。
老师没有过多展开另外两个,于是课后我自己查了一下资料。
1.面向过程编程Procedure Oriented Programming(POP):
分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。常见的有C语言。
//1.面向过程编程
//按照步骤一步一步来的
let num1 = 2
let num2 = 3
let sum = num1 + num2
console.log(sum)
2.面向对象编程Object Oriented Programming(OOP):
把构成问题的事务分解成各个对象和类,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行,通过封装继承和多态来演示是事物事件的联系。常见的有C++、C#、Java
面向对象编程小例子解析
3.函数式编程Functional Programming(FP):
虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。
我们首先要搞明白计算机(Computer)和计算(Compute)的概念。在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。
程序的本质:根据输入通过某种运算获得相应的输出,程序开发过程中涉及到很多输入和输出的函数。
函数式编程中的函数指的不是程序中的函数(方法),而是数学中的函数映射关系。
函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数。
// 3.函数式编程
// 有着可变的输入,一个映射关系,获得输出。并且相同输入只会得到一个输出。
function add (n1, n2) {
return n1 + n2
}
let sum = add(2, 3)
console.log(sum)
二、函数是一等公民 First-class Function(头等函数)
当一门编程语言的函数可以被当作变量一样用时,则称这门语言拥有头等函数(javascript就是拥有头等函数)。
- 函数可以被赋值给一个变量
- 函数可以被当作参数传递给其他函数
- 函数可以作为另一个函数的返回值
1.函数作为变量
// 把函数赋值给变量
let fn = function () {
console.log('Hello First-class Function') }
fn()
// 一个示例
const BlogController = {
index (posts) { return Views.index(posts) },
show (post) { return Views.show(post) },
create (attrs) { return Db.create(attrs) },
update (post, attrs) { return Db.update(post, attrs) }, destroy (post) { return Db.destroy(post) }
}
// 优化
const BlogController = {
index: Views.index,
show: Views.show,
create: Db.create,
update: Db.update,
destroy: Db.destroy
22
}
2.高阶函数 (Higher-order function)
即
- 可以把函数作为参数传递给另一个函数
- 可以把函数作为另一个函数的返回结果
函数作为参数
好处:更加灵活,不用在意被调用的函数内部具体实现的细节。
//DEMO1
// forEach遍历数列中每一项
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)
})
//DEMO2
// filter 返回满足fn的数字
function filter (array, fn) {
let results = []
for (let i = 0; i < array.length; i++) {
if (fn(array[i])) {
results.push(array[i])
}
}
return results
}
//上课测试样例,需要返回能被2整除的数字
let arr = [1, 3, 4, 7, 8]
let result = filter(arr, function (item){return item % 2 === 0})
console.log(result)
实际测试结果:
函数作为返回值
//高阶函数——函数作为返回值
function makeFn () {
let msg = 'Hello function'
return function () {
console.log(msg)
}
}
//调用方法1
const fn = makeFn()
fn()
//无效调用方法,因为makeFn()调用之后返回的是一个函数,需要再加一个括号获得函数返回的东西。
makeFn()
//调用方法2
makeFn()()
实际测试结果(每次都把另外两种调用方法注释掉):
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} RMB`)
})
pay(5)
pay(5)
pay(5)
pay(5)
pay(5)
实际测试结果:
使用高阶函数的意义
- 抽象可以帮我们屏蔽细节,只需要关注与我们的目标
- 高阶函数是用来抽象通用的问题
- 使得我们代码更加简洁
3.常用高阶函数模拟
-
forEach
forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
注意: forEach() 对于空数组是不会执行回调函数的。
前面其实已经模拟过forEach了,这边只是把上面那段代码copy过来。
//DEMO1
// forEach遍历数列中每一项
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)
})
-
map
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
注意: map() 不会对空数组进行检测。
注意: map() 不会改变原始数组。
本人第一次模拟的
//map
// mao方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
function map (array, fn) {
let resultArr = []
for (let i = 0; i < array.length; i++) {
resultArr.push(fn(array[i]))
}
return resultArr
}
let arr = [1, 2, 3, 4]
let result = map(arr, function(item){
return item * item;
})
console.log(result)
结果:
返回结果正确是正确,但是看了老师的发现我并没有用到箭头函数。顺便简单补习了一下,为什么要用箭头函数。
箭头函数优点:
1.代码更简洁
2.箭头函数不会绑定this
。 或者说箭头函数不会改变this
本来的绑定。
JavaScript初学者必看”箭头函数“
于是跟着跟着老师又把map模拟重新写了一遍。
//使用箭头函数
var map = (array, fn) => {
let resultArr = []
for (let value of array) {
resultArr.push(fn(value))
}
return resultArr
}
let arr = [1, 2, 3, 4]
let result = map(arr, v => v * v);
console.log(result);
运行结果:
-
filter
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
注意: filter() 不会对空数组进行检测。
注意: filter() 不会改变原始数组。
也是copy了一下上面的代码。
//DEMO2
// filter 返回满足fn的数字
function filter (array, fn) {
let results = []
for (let i = 0; i < array.length; i++) {
if (fn(array[i])) {
results.push(array[i])
}
}
return results
}
//上课测试样例,需要返回能被2整除的数字
let arr = [1, 3, 4, 7, 8]
let result = filter(arr, function (item){return item % 2 === 0})
console.log(result)
-
every
every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。
every() 方法使用指定函数检测数组中的所有元素:
- 如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
- 如果所有元素都满足条件,则返回 true。
注意: every() 不会对空数组进行检测。
注意: every() 不会改变原始数组。
//DEMO6
//every
//我自己写的
var every = (array, fn)=>{
for (let value of array) {
if(!fn(value)){
return false;
}
}
return true;
}
//老师的every代码
const every = (array, fn) => {
let result = true
for (const value of array) {
result = fn(value)
if (!result) {
break
}
}
return result
}
let arr = [11 ,12, 14]
let r = every(arr, v => v > 10)
console.log(r)
let r2 = every(arr, v => v > 11)
console.log(r2)
测试结果:
-
some
some() 方法用于检测数组中的元素是否满足指定条件(函数提供)。
some() 方法会依次执行数组的每个元素:
- 如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
- 如果没有满足条件的元素,则返回false。
注意: some() 不会对空数组进行检测。
注意: some() 不会改变原始数组。
//DEMO7
//some
//我自己写的
var some = (array, fn)=>{
for (let value of array) {
if(fn(value)){
return true;
}
}
return false;
}
//老师的代码
const some = (array, fn) => {
let result = false
for (const value of array) {
result = fn(value)
if (result) {
break
}
}
return result
}
let arr = [11 ,12, 14]
let r = some(arr, v => v < 10)
console.log(r)
let r2 = some(arr, v => v < 12)
console.log(r2)
let arr2 = [1,3,5,9]
let r3 = some(arr2, v => v % 2 === 0)
console.log(r3)
let arr3 = [1,3,4,9]
let r4 = some(arr2, v => v % 2 === 0)
console.log(r4)
测试结果:
除了上述直接引用外的参考资料:
1.购买的拉勾网《大前端训练营》课程
2.廖雪峰 JavaScript Python Git 教程——函数式编程
https://www.kancloud.cn/wizardforcel/liaoxuefeng/108521
3.MDN First-class Function(头等函数)
https://developer.mozilla.org/zh-CN/docs/Glossary/First-class_Function
以上是关于进阶学习1:函数式编程FP——概念头等函数高阶函数常用高阶函数模拟的主要内容,如果未能解决你的问题,请参考以下文章
进阶学习4:函数式编程FP——函子FunctorMayBe函子Either函子IO函子FolktalePointer函子Monad