当前位置: 首页 > news >正文

函数式编程思想

如果你刚开始学习编程,决定先学习哪一种 **编程范式(Programming Paradigm )**和编程语言可能会比较困难。

如果你想掌握一种在当今技术环境中非常重要的编程范式,可以考虑学习函数式编程(Functional Programming)

它是一种更简单、更干净、更可预测的编程方式,同时代码也更容易测试和维护

那么,函数式编程到底是什么?接下来我将介绍这种编程范式、它的优势,以及最流行的函数式编程语言。

什么是函数式编程

函数式编程(FP)是一种软件开发方法,它使用纯函数来创建可维护的软件。换句话说,它通过函数组合来构建程序。

函数式编程借助语言支持,将函数用作变量、参数和返回值,在此过程中创建出优雅简洁的代码。函数式编程还使用不可变数据,避免共享状态等概念。这与面向对象编程(OOP)形成对比,后者使用可变数据和共享状态。

函数也被视为一等公民,这意味着它们可以作为参数传递、从其他函数返回,还能关联到名称上。

函数式编程关注结果而非过程,并且不支持循环语句和条件语句(例如 If-Else)之类的迭代结构。如今许多主流编程语言,包括 C#、Java、JavaScript、PHP 和 Python,都支持函数式风格的编程或采用了函数式编程中的特性。

一个简单的例子如下:

let numbers = [1,2,3,4] let result = [] for(let i = 0; i < numbers.length; i++){ result.push(numbers[i] * 2) } // 以下是函数式子写法 const numbers = [1,2,3,4] const result = numbers.map(n => n * 2)

函数式编程主要有几个核心思想:

  1. 纯函数(Pure Function)
  2. 不可变数据(Immutable Data)
  3. 高阶函数(Higher-order Function)
  4. 函数组合(Function Composition)
  5. 柯里化(Currying)

接下来我们按照顺序一一讲述。

纯函数式编程

在函数式编程中,**纯函数(Pure Function)**是最核心的概念之一。

一个函数如果满足以下两个条件,就可以称为纯函数:

  1. 相同输入 → 相同输出
  2. 没有副作用(Side Effects)

也就是说,函数的返回值只由输入参数决定,不会依赖外部环境,也不会改变外部状态。

function add(a,b){ return a + b }

副作用是指:

函数在执行时,改变了函数外部的状态,或者依赖外部状态。

例如:

  • 修改全局变量
  • 修改对象属性
  • 发送网络请求
  • 操作 DOM
  • 写入数据库
  • 输出日志

这些行为都会让函数的行为变得不可预测

以下例子

函数add()修改了外部变量total。这样就算带来了副影响

let total = 0 function add(a){ total += a }

下面是一个非纯函数的例子:

constmyAddresses= ["ChurchSt.","CovingtonCross"]; functionupdateMyAddress(newAddress) { myAddresses.push(newAddress); return myAddresses; }

这个函数是非纯函数,因为:它修改了函数外部的变量myAddresses。这种行为会产生副作用(side effects)

纯函数很重要是因为

  1. 可预测:输入相同,结果一定相同。
  2. 更容易测试:测试纯函数非常简单
  3. 更容易维护:纯函数不会修改外部状态
  4. 更加适合并发,纯函数没有共享状态

不可变数据(Immutable Data)

在函数式编程中,一个非常重要的原则是:

数据一旦创建,就不应该被修改。

如果需要改变数据,我们应该:

创建新的数据,而不是修改原来的数据。

这种思想叫做不可变数据(Immutable Data)

错误写法(修改原来的对象):

const user = { name: "Tom", age: 18 } user.age = 20 console.log(user)

上面这个问题,原对象已经被改变了。如果这个user在程序的其他地方也被使用,就可能导致不可预测的问题

函数式写法:

const newUser= { ...user, age:20 }

上面这里使用了对象展开运算符(Spread Operator)

它的作用是:

  1. 复制原对象
  2. 修改需要改变的字段
  3. 返回一个新对象

那么为什么我们需要这种不可变数据,因为

  1. 代码更加安全,不会被其他代码意外修改
  2. 更加容易调试,数据改变时一定是创建了新的对象
  3. 更加适合函数式编程,如果数据可变,容易产生副作用,但是函数式编程强调没有副作用

数组中的不可变写法

// 错误写法 arr.push(4) //正确写法: const newArr = [...arr, 4]

在前端开发中,推荐使用:

  • ...扩展运算符
  • map
  • filter
  • concat

来操作数据,而不是直接修改对象或数组。

高阶函数

高阶函数指的是:

函数可以作为参数传递,或者函数可以返回另一个函数。

也就是说满足两个条件

  1. 接收函数作为参数
  2. 返回一个新的函数

下面是一个简单的例子

function calculate(fn, value){ return fn(value) } function square(n){ return n * n } calculate(square,5)

代码执行流程:

  1. square函数被传入calculate
  2. calculate内部执行fn(value)
  3. 实际执行的是square(5)

最终结果:

25

这里的calculate就是一个高阶函数

函数返回函数

高阶函数的另一种形式是:

**函数返回另一个函数。**例如:

functionmultiply(x){ return function(y){ return x*y } } const double = multiply(2) double(5)

执行流程:

multiply(2) -> 返回一个函数 double(5) -> 2 * 5

结果:

10

这种写法在函数式编程中非常常见。

为什么高阶函数很重要,首先就是更加灵活,可以同一个函数去完成不同的任务。

calculate(square,5) calculate(Math.sqrt,9)

其次就是我们可以把一些通用逻辑写在高阶组件中

function repeat(fn, times){ for(let i = 0; i < times; i++){ fn(i) } } repeat(console.log,3)

函数组合

函数式编程中一个非常重要的思想是函数组合(Function Composition)

函数组合的意思是:

把多个小函数组合起来,形成一个新的函数。

在数学中也有类似的概念:

一个函数的输出可以作为另一个函数的输入。

const add = x => x + 1 const multiply = x => x * 2 const result = multiply(add(5)) const result2 = add(multiply(3))

函数组合可以让程序变得更加模块化,让每一个函数就负责去执行一个简单任务,然后再把函数组合在一起

同时,小函数可以被用在多个地方,更容易被复用

const add1 = x => x + 1 add1(5) add1(10) add1(100)

最后就是这种写法更加符合函数式编程思想

函数式编程强调:

使用很多小函数组合成复杂逻辑。

而不是写一个巨大函数。

多个函数组合案例

const add1 = x => x + 1 const multiply = x => x * 2 const minus3 = x => x - 3 const result = minus3(multiply(add1(5))) const result = users .filter(user => user.age > 18) .map(user => user.name) //这里都算函数组合,数据会一步步被处理

柯里化

柯里化(Currying)的核心思想是:

把一个接收多个参数的函数,转换成多个只接收一个参数的函数。

简单来说:

f(a,b,c) // 转换成如下形式 f(a)(b)(c)

一个案例

function add(a, b) { return a + b } add(2,3) // 如果使用柯里化,将变成如下形式 function add(a){ return function(b){ return a + b } } add(2)(3)

使用箭头函数写柯里化

在 JavaScript 中,柯里化通常用箭头函数写得更简洁:

const add =a => b =>a+b add(2)(3)

这其实等价于:

function add(a){ return function(b){ return a+b } }

柯里化的作用

柯里化最大的作用是:

1 参数复用

const multiply = a => b =>a*b const double=multiply(2) const triple=multiply(3) double(5) triple(5)

执行结果:

double(5) -> 10 triple(5) -> 15

这里:

multiply(2)

生成了一个新的函数double

这样可以复用参数。


2 提高函数复用性

例如:

const greaterThan=a =>b =>b>a

使用:

const greaterThan10=greaterThan(10) greaterThan10(20) greaterThan10(5)

结果:

true false

这样可以快速创建很多不同的函数。


3 更适合函数组合

柯里化可以更容易配合函数组合。

例如:

const add = a =>b => a+b const multiply = a => b =>a*b

可以组合使用:

multiply(2)(add(3)(5))

执行过程:

add(3)(5) = 8 multiply(2)(8) = 16

map / filter / reduce

在 JavaScript 中,数组提供了很多函数式方法,其中最常用的三个是:

  • map
  • filter
  • reduce

它们都是高阶函数,因为它们接收函数作为参数

这三个方法是函数式编程中处理数据最常见的方式。

map

map的作用是:

对数组中的每个元素进行处理,并返回一个新的数组。

例如:

const numbers= [1,2,3,4] const result=numbers.map(n =>n*2)

执行流程:

1 * 2 2 * 2 3 * 2 4 * 2

结果:

[2,4,6,8]

注意:

  • map不会修改原数组
  • 它会返回一个新的数组

这符合函数式编程中的不可变数据原则

filter

filter的作用是:

根据条件筛选数组中的元素。

const numbers= [1,2,3,4,5] const result=numbers.filter(n => n > 3)

执行流程:

1 > 3 × 2 > 3 × 3 > 3 × 4 > 3 √ 5 > 3 √

结果:

[4,5]

reduce

reduce的作用是:

把数组“归约”为一个值。

例如计算数组的总和:

const numbers= [1,2,3,4] const sum= numbers.reduce((pre, cur) => { return pre+ cur },0)

执行过程:

0 + 1 = 1 1 + 2 = 3 3 + 3 = 6 6 + 4 = 10

结果:

10

reduce的第一个参数是一个函数:

(total,current) =>total+current

第二个参数是初始值:

0
方法作用
map转换数据
filter筛选数据
reduce归约数据
http://www.jsqmd.com/news/466533/

相关文章:

  • 2026钻床市场热门:这些工厂钻床受追捧,目前优质的钻床品牌技术引领与行业解决方案解析 - 品牌推荐师
  • 汇源全屋定制作为全屋定制专业制造商,价格大概多少钱? - 工业推荐榜
  • 基于改进粒子群算法的含碳捕集微网多时间尺度低碳经济调度(Matlab代码实现)
  • Flutter 三方库 system_resources_2 的鸿蒙化适配指南 - 实时监控鸿蒙端侧 CPU 负载、内存占用与系统资源动态感知
  • 星焰家居这个不锈钢全屋定制厂商品牌靠不靠谱,值得推荐吗? - myqiye
  • 2026年热门的CNC 精密压铸加工公司推荐:医疗设备精密压铸加工/智能家居精密压铸加工采购指南厂家怎么选 - 行业平台推荐
  • # 发散创新:WebHID 在浏览器端实现外设通信的全新实践 在现代Web 开
  • 2026年评价高的储能弹簧工厂推荐:耐腐蚀弹簧/小家电电磁阀弹簧/高压直流继电器弹簧精选厂家推荐 - 行业平台推荐
  • Python开发英语记忆单词软件 - 优化
  • FFMpeg + WebSocket + JSMpeg 搭建低延迟视频系统(总览篇)
  • 2026年01月深圳CE:加速寿命试验/合规类/国内外认证/机构类/测试服务/温度老化试验/电子电气检测/腐蚀试验/选择指南 - 优质品牌商家
  • 2026国内小白纹绣培训重实操机构推荐榜:野生眉学校、零基础学纹眉、零基础小白、零基础纹眉学校、零结痂雾眉、韩式定妆学校选择指南 - 优质品牌商家
  • PAT 乙级 1078
  • 谁懂啊!OpenClaw(小龙虾)爆火不是没道理
  • Python基于flask的博客系统设计与实现
  • 总结AI蓝牙音箱生产厂,国内靠谱厂家Top10有哪些? - 工业品网
  • Flutter 三方库 shelf_cors_headers 的鸿蒙化适配指南 - 实现具备跨域安全访问策略的服务端拦截器、支持端侧微服务网关与分布式请求治理实战
  • 聊聊扬州月子中心按需定制,哪家品牌靠谱又有高性价比? - 工业设备
  • win11下解决eNSP AR启动40/41错误解决方案
  • Flutter 三方库 health_connector_core 的鸿蒙化适配指南 - 实现具备跨平台标准的数据采集与同步架构、支持端侧健康指标建模与设备总线协同实战
  • 牛客练习001:反转链表
  • 基于Matlab 2017a的单相交交变频电路仿真研究:阻感负载下的傅立叶分析与原理讲解
  • python flask django教师教学计划系统 计算机科学拔尖学生培养基地
  • Python基于flask的图书借阅系统的设计与实现_
  • 30 分钟搭出你自己的 OpenClaw:保姆级安装教程(2026版)
  • python flask django考研学习资料商城信息服务平台
  • 哪些被动式窗供应商在2026年收获好评如潮?高端定制门窗/智能门窗/安全门窗/全屋门窗,被动式窗供应商推荐榜单 - 品牌推荐师
  • 避坑局!为了跑 OpenClaw 花一万买 Mac?醒醒吧!腾讯云 vs 阿里云一键部署终极对比(打工人搞钱必看)
  • 2026煤矿井下液压支架填充物优质厂商推荐:聚氨酯发泡填充块/聚氨酯发泡填充物/阻燃填充物/抗静电填充物/柱窝填充块/选择指南 - 优质品牌商家
  • 互联网大厂Java面试实录:从Spring Boot到微服务架构的深度剖析