什么是函数式编程?实用指南

从最早的时候开始,函数式编程就已经成为软件开发中的一种潮流,但是在现代时代中,它已经具有了新的重要性。本文着眼于函数式编程背后的概念,并通过JavaScript和Java中的示例提供了实用的理解。

定义功能性程序设计

功能是代码组织的基础;它们以所有更高阶的编程语言存在。通常,功能编程是指以最佳效果使用功能来创建干净且可维护的软件。更具体地,功能编程是一组编码方法,通常被描述为编程范例

 

有时与面向对象的编程(OOP)和过程式编程相反地定义函数式编程。这是一种误导,因为这些方法不是互斥的,并且大多数系统倾向于同时使用这三种方法。

函数式编程在某些情况下具有明显的好处,它在许多语言和框架中得到了广泛使用,并且在当前的软件趋势中尤为突出。它是一个有用且强大的工具,应该成为每个开发人员的概念和语法工具包的一部分。

纯功能

函数式编程中的理想选择是所谓的纯函数。纯函数是一种纯函数,其结果仅取决于输入参数,并且其操作不会引起副作用,也就是说,除了返回值之外,不会产生任何外部影响。

纯功能的美在于其结构的简单性。由于纯函数仅归纳为参数和返回值(即其API),因此可以将其视为复杂性的死胡同:它与所运行的外部系统的唯一交互是通过已定义的API。

这与OOP相对,在OOP中,对象方法被设计为与对象(对象成员)的状态进行交互,而在过程式代码中,外部状态通常是从函数内部进行操作的。

 

但是,在实际实践中,功能通常最终需要与更广泛的上下文进行交互,如React的useEffect钩子所证明的那样。

不变性

函数式编程原理的另一个原则是不要在函数外修改数据。实际上,这意味着避免修改函数的输入参数。相反,函数的返回值应反映完成的工作。这是避免副作用的一种方法。当在较大的系统中运行该功能时,可以更轻松地推断该功能的影响。

一流的功能

除了纯粹的函数理想之外,在实际的编码实践中,函数式编程还取决于一流的函数。头等功能是被视为“本身的东西”的功能,能够独立存在并被独立对待。函数式编程试图利用语言支持,将函数用作变量,参数和返回值来创建优美的代码。

由于一流的功能是如此灵活和有用,因此甚至强大的OOP语言(如Java和C#)也已经迁移到了一流的功能支持中。这就是Java 8'对Lambda表达式的支持的推动力。

描述第一类函数的另一种方法是将函数作为数据。也就是说,可以将一级函数分配给变量,就像其他任何数据一样。在编写时,let myFunc = function(){}您正在使用函数作为数据。

高阶函数

接受函数作为参数或返回函数的函数称为高阶函数,即对函数进行操作的函数。

近年来,JavaScipt和Java都添加了改进的函数语法。Java添加了箭头运算符和双冒号运算符。JavaScript添加了箭头运算符。这些运算符旨在使定义和使用函数(尤其是内联作为匿名函数)更加容易。匿名函数是在没有给其引用变量的情况下定义和使用的。

函数式编程示例:集合

函数式编程最杰出的例子也许就是处理集合。这是因为能够在集合中的各个项目之间应用功能块很自然地适合于纯功能思想。

考虑清单1,该清单利用JavaScriptmap()函数将数组中的字母大写。

清单1.在JavaScript中使用map()和一个匿名函数

让字母= [“ a”,“ b”,“ c”];
console.info(letter.map((x)=> x.toUpperCase())); //输出[“ A”,“ B”,“ C”]

这种语法的优点在于,代码紧密集中。不需要命令性的管道,例如循环和数组操作。此代码清楚地表达了正在做的事情的思考过程。

如清单2所示,使用Java的arrow运算符可以实现相同的目的。

清单2.在Java中使用map()和一个匿名函数

导入java.util。*; 
导入java.util.stream.Collectors;
导入静态java.util.stream.Collectors.toList;
// ...
较低的列表= Arrays.asList(“ a”,“ b”,“ c”);
System.out.println(lower.stream()。map(s-> s.toUpperCase())。collect(toList())); //输出[“ A”,“ B”,“ C”]

清单2使用Java 8的流库来执行相同的任务,即对字母列表进行大写。注意,核心箭头运算符的语法实际上与JavaScript相同,它们执行相同的操作,即创建一个接受参数,执行逻辑并返回值的函数。(重要的是要注意,如果这样定义的函数体周围没有花括号,那么将自动给出返回值。)

继续使用Java,请考虑清单3中的double Colon运算符。该运算符允许您在类上引用一个方法:在这种情况下,toUpperCase是String类上的方法。清单3与清单2做同样的事情。不同的语法在不同的情况下派上用场。

 

清单3. Java Double Colon运算符

// ...
列出上层= Lower.stream()。map(String :: toUpperCase).collect(toList());

在以上所有三个示例中,您可以看到高阶函数正在起作用。map()两种语言的函数均接受函数作为参数。

换句话说,您可以将函数作为函数接口传递给其他函数(在Array API或其他方式中)。提供程序功能(使用参数功能)是通用逻辑的插件。

这看起来很像OOP中的策略模式(实际上,在Java中,在幕后生成了具有单个方法的接口),但是函数的紧凑性使得组件协议非常紧凑。

再举一个例子,考虑清单4,它在Express框架中为Node.js定义了一个路由处理程序。

清单4. Express中的功能性路由处理程序

var express = require('express');
var app = express();
app.get('/',函数(req,res){
  res.send('One Love!');
});

清单4是函数式编程的一个很好的例子,它允许对路由映射以及处理请求和响应所需要的内容进行清晰的定义-尽管可能会争辩说在函数体内操纵响应对象是一个副作用。 。

咖喱函数

现在考虑返回函数的函数的函数编程概念。这比作为参数的函数要少见。清单5给出了一个常见的React模式的示例,其中胖箭头语法是链接在一起的。

清单5. React中的一个咖喱函数

handleChange =字段=> e => {
e.preventDefault();
//处理事件
}

上面的目的是创建一个事件处理程序,该处理程序将接受所讨论的字段,然后接受该事件。这很有用,因为您可以将其handleChange应用于多个字段。简而言之,同一处理程序可在多个字段上使用。

清单5是一个curried函数的示例。“ Curried function”有点令人沮丧。它表彰一个人,这很好,但是没有描述这个概念,这很令人困惑。无论如何,这种想法是,当您拥有返回函数的函数时,可以比创建具有多个参数的单个函数更灵活的方式将对它们的调用链接在一起。

在调用这些类型的函数时,您将遇到独特的“链括号”语法:handleChange(field)(event)

大型编程

前面的示例提供了在有针对性的上下文中对函数式编程的动手理解,但是函数式编程旨在为大型编程带来更大的好处。换句话说,函数式编程旨在创建更清洁,更具弹性的大规模系统。

很难提供示例,但是一个现实世界的实例是React推广功能组件的举动。React团队已经注意到,更简洁的组件功能样式带来的好处是随着接口体系结构的增大而复合。

ReactiveX是另一个大量使用函数式编程的系统。基于ReactiveX使用的那种事件流构建的大规模系统可以受益于软件组件交互的解耦。Angular全面采用ReactiveX(RxJS)作为对这种功能的认可。

范围和上下文可变

最后,变量作用域和上下文是一个不一定是函数式编程范式一部分的问题,但在进行函数式编程时要注意的一个非常重要的问题。

在JavaScript中,上下文明确表示this关键字可以解析的内容。就JavaScript箭头运算符而言,this指的是封闭上下文。使用传统语法定义的函数会接收其自己的上下文。DOM对象上的事件处理程序可以利用这一事实来确保this关键字引用所处理的元素。

 

范围是指变量范围,即可见的变量。对于所有JavaScript函数(fat-arrow和传统)以及Java的箭头定义的匿名函数,范围是封闭函数体的范围-尽管在Java中,只有那些有效的final变量才可以是访问。这就是为什么将此类功能称为闭包的原因。该术语表示功能包含在其包含的范围内。

重要的是要记住:此类匿名函数具有对作用域中的变量的完全访问权限。内部函数可以针对外部函数的变量进行操作。这可以被认为是非纯功能的副作用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值