函数式编程

函数式编程意味着使用函数来创建干净且可维护的软件的最佳效果。函数式编程从一开始就一直是软件开发的潮流,但在现代具有新的重要性。本文着眼于函数式编程背后的概念,并通过 JavaScript 和 Java 中的示例提供实际理解。

函数式编程定义

函数是代码组织的基础;它们存在于所有高阶编程语言中。一般来说,函数式编程意味着使用函数来创建干净且可维护的软件的最佳效果。更具体地说,函数式编程是一组编码方法,通常被描述为一种编程范式。
函数式编程有时被定义为与面向对象编程 (OOP) 和过程式编程相对立。这是一种误导,因为这些方法并不是相互排斥的,而且大多数系统倾向于同时使用这三种方法。
白嫖资料
函数式编程在某些情况下提供了明显的好处,它在许多语言和框架中被大量使用,并且在当前的软件趋势中很突出。它是一个有用且强大的工具,应该成为每个开发人员的概念和语法工具包的一部分。

纯函数

函数式编程的理想是所谓的纯函数。纯函数是一种结果仅取决于输入参数的函数,并且其操作不会引发副作用,即除了返回值之外不产生任何外部影响。
白嫖资料
纯函数的美妙之处在于其架构的简单性。因为一个纯函数被简化为只有参数和返回值(即它的 API),所以它可以被视为一个复杂的死胡同:它与它运行的外部系统的唯一交互是通过定义的 API。

这与 OOP 形成对比,在 OOP 中,对象方法被设计为与对象(对象成员)的状态交互,与过程式代码形成对比,后者通常从函数内部操纵外部状态。

不变性

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

一级功能

除了纯函数理想之外,在实际编码实践中,函数式编程取决于一等函数。一等函数是被视为“事物本身”的函数,能够独立存在并被独立处理。函数式编程试图利用语言支持将函数用作变量、参数和返回值来创建优雅的代码。
白嫖资料
因为一流的函数是如此灵活和有用,即使是像 Java 和 C# 这样的强 OOP 语言也已经转向合并一流的函数支持。这就是 Java 8 支持 Lambda 表达式背后的推动力。

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

高阶函数

接受函数作为参数或返回函数的函数称为高阶函数——对函数进行运算的函数。

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

函数式编程示例:集合
也许函数式编程最突出的例子是处理集合。这是因为能够跨集合中的项目应用功能块是纯函数思想的自然契合。

在 JavaScript 中使用 map() 和匿名函数

let letters = ["a", "b", "c"];
console.info( letters.map((x) => x.toUpperCase()) ); // outputs ["A", "B", "C"]

这种语法的美妙之处在于代码非常集中。不需要命令式管道,例如循环和数组操作。这段代码清楚地表达了正在做的事情的思考过程。

使用 Java 的箭头运算符可以实现相同的目的
白嫖资料

在 Java 中使用 map() 和匿名函数

import java.util.*; 
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
//...
List lower = Arrays.asList("a","b","c");
System.out.println(lower.stream().map(s -> s.toUpperCase()).collect(toList())); // outputs ["A", "B", "C"]

使用 Java 8 的流库来执行大写字母列表的相同任务。请注意,核心箭头运算符语法实际上与 JavaScript 相同,它们做同样的事情,即创建一个接受参数、执行逻辑并返回值的函数。(重要的是要注意,如果这样定义的函数体周围缺少大括号,则自动给出返回值。)

继续 Java,考虑双冒号运算符。该运算符允许您引用类上的方法:在本例中,toUpperCase是 String 类上的方法。不同的语法适用于不同的场景。

// ...
List upper = lower.stream().map(String::toUpperCase).collect(toList());

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

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

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

作为另一个示例,它在 Node.js 的 Express 框架中定义了一个路由处理程序。

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

函数式编程的一个很好的例子,因为它允许对映射路由和处理请求和响应所需的确切定义进行清晰的定义——尽管可能有人认为在函数体内操作响应对象是一种副作用.

React 中的柯里化函数

handleChange = field => e => {
e.preventDefault();
// Handle event
}

上面的目的是创建一个事件处理程序,它将接受有问题的字段,然后是事件。这很有用,因为您可以将其handleChange应用于多个字段。简而言之,同一个处理程序可用于多个字段。无论如何,我们的想法是,当您有返回函数的函数时,您可以将调用链接在一起,这比创建具有多个参数的单个函数更灵活。

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

大范围编程

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

很难提供这方面的例子,但一个真实的例子是 React 推广功能组件的举措。React 团队已经注意到,组件的更简洁的功能风格提供了随着界面架构变得更大而复合的好处。

另一个大量使用函数式编程的系统是ReactiveX。建立在 ReactiveX 使用的那种事件流上的大型系统可以从解耦的软件组件交互中受益。Angular 全面采用 ReactiveX (RxJS) 作为对这种能力的认可。

变量范围和上下文

作为范式不一定是函数式编程的一部分,但在进行函数式编程时需要注意的一个问题是变量范围和上下文。

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

最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。 可以的话请给我一个三连支持一下我哟,我们下期再见

白嫖资料

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值