최근에 함수형 프로그래밍의 고전 입문을 읽고 있는데, 관심이 있거나 필요하신 분은 한 번 읽어보셔도 좋습니다.
1. 함수형 프로그래밍이란
함수형 프로그래밍은 주로 수학적 함수와 그 개념을 기반으로 하기 때문에 먼저 수학에서의 함수, 즉
y = f(x)
, 즉 함수 f를 살펴보겠습니다. (x)는 x를 매개변수로 사용하고 y는 임의의 숫자일 수 있습니다. 여기에는 다음과 같은 몇 가지 핵심 사항이 포함됩니다.
1. 함수는 항상 값을 반환해야 합니다. 3. 함수는 수신된 매개변수에 따라 실행되어야 합니다(예: 이 함수를 분석하려면 먼저 세 번째 항목을 살펴보십시오. 함수는 외부 환경이 아닌 수신된 매개변수에 따라 실행되어야 합니다. 여기서 계산Tax 함수는 외부 백분율값에 의존합니다. 따라서 이 함수는 수학적 의미에서 함수라고 부를 수 없습니다. 그러면 어떻게 수학적 의미에서 함수로 변환할 수 있습니까? 매우 간단합니다
varcalculateTax = (value,percentValue) =>{return value/100 * (100 + ratesValue)};
이제 이 함수를 실제 함수라고 부를 수 있습니다.
2. 참조 투명성
함수 정의에 따르면 모든 함수는 동일한 입력 및 출력에 대해 동일한 값을 반환한다고 결론을 내릴 수 있습니다. 함수의 이러한 속성을 참조 투명성이라고 합니다
// 一个计税函数 var percentValue = 5; var calculateTax = (value) => {return value/100 * (100 + percentValue)};
var identity = (i) => { return i };
sum(4,5) + identity(1);
3. 함수형, 선언형 및 추상형
함수형 프로그래밍은 선언형 프로그래밍과 추상 코드 작성을 옹호합니다.
sum(4,5) + 1;
var array = [1,2,3]; for(let i = 0; i < array.length; i++){ console.log(array[i]) }
위 코드에서는 배열 길이 가져오기, 배열 반복, 인덱스를 사용하여 배열 요소 가져오기 등을 제거했습니다. 우리는 무엇을 해야 할지(예: 배열 요소 인쇄), 배열 길이 가져오기, 루핑 등 모든 작업을 기계에서 수행하지만, 수행 방법에만 관심을 두면 됩니다. 선언적 프로그래밍
함수형 프로그래밍 제안 코드의 다른 곳에서 재사용할 수 있는 추상적인 방식으로 함수를 만듭니다.
4. 순수함수
순수함수란 무엇인가요? 순수 함수 함수는 주어진 입력에 대해 동일한 출력을 반환합니다. 예를 들어
var arr = [1,2,3]; arr.forEach((ele) => { console.log(ele) })
1.4.1 순수 함수는 테스트 가능한 코드를 생성합니다불순한 함수에는 부작용이 있습니다. 이전 세금 계산 함수를 예로 들어 보겠습니다.
var double = (value) => value * 2;
이 함수는 주로 외부 환경에 따라 달라지기 때문에 순수 함수가 아닙니다. 그 논리를 계산하고 외부 환경이 바뀌면 결과에 영향을 미칩니다. 따라서 순수 함수의 주요 특징은 외부 변수에 의존하지 않으며 외부 변수를 변경해서는 안 된다는 것입니다. 외부 변수를 변경하면 다른 기능의 동작이 변경될 수 있습니다. 즉, 시스템 동작을 예측할 수 없게 만드는 부작용이 발생할 수 있습니다.
1.4.2 합리적인 코드
이중함수 등 이름을 통해 함수의 기능을 유추해야 합니다var double = (value) => value * 2;
我们可以通过函数名轻易的推出这个函数会把给定的数值加倍,因此根据引用透明性,我们可以直接把 double(5) 替换成 10。还有一个例子,Math.max(3,4,5,6) 结果是什么?虽然我们只看到了函数的名字,但是我们很容易看出结果,我们看到实现了吗?并没有,为什么,就是因为 Math.max 是纯函数啊!!!
5、 并发代码
纯函数允许我们并发的执行代码,因为纯函数不会改变它的环境,这意味着我们根本不需要担心同步问题。当然,js 是单线程的,但是如果项目中使用了 webworker 来并发执行任务,该怎么办?或者有一段 Node 环境中的服务端代码需要并发的执行函数,又该怎么办呢?
// 非纯函数代码 let global = 'something' let function1 = (input) => { // 处理 input // 改变 global global = "somethingElse" } let function2 = () => { if(global === "something"){ // 业务逻辑 } }
如果我们需要并发的执行 function1 和 function2,假设 function1 在 function2 之前执行,就会改变 function2 的执行结果,所以并发执行这些代码就会造成不良的影响,现在把这些函数改为纯函数。
let function1 = (input,global) => { // 处理 input // 改变 global global = "somethingElse" } let function2 = (global) => { if(global === "something"){ // 业务逻辑 } }
此处我们把 global 作为两个函数的参数,让它们变成纯函数,这样并发执行的时候就不会有问题了。
6、可缓存
既然纯函数对于给定的输入总能返回相同的输出,那么我们就能缓存函数的输出,例如
var doubleCache = (value) => { const cache = {}; return function(value){ if(!cache[value]){ cache[value] = value * 2 console.log('first time') } return cache[value]; } } var double = doubleCache(); double(2) // first time,4 double(2) // 4 // 或者直接使用立即执行函数 var double = ((value) => { const cache = {}; return function(value){ if(!cache[value]){ cache[value] = value * 2 console.log('first time') } return cache[value]; } })() double(2) // first time,4 double(2) // 4
这个函数中,假设我们第一次输入 5,cache 中并没有,于是执行代码,由于闭包的存在,cache[5] = 10,第二次我们调用的时候,cache[5] 存在,所以直接 return 10,看到了吗?这就是纯函数的魅力!!!别忘记这是因为纯函数的引用透明性。
7、 管道与组合
纯函数应该被设计为一次只做一件事,并且根据函数名就知道它所做的事情。
比如 linux 系统下有很多日常任务的命令,如 cat 用于打印文件内容,grep 用于搜索文件,wc 用于计算行数,这些命令一次只解决一个问题,但是我们可以用管道或组合来完成复杂的任务。假设我们需要在一个文件中找到一个特定的名称并统计它的出现次数,在命令行要输入如下指令
cat jsBook | grep -i “composing” | wc
上面的命令通过组合多个函数解决了我们的问题。组合不是 linux 命令独有的,它们是函数式编程范式的核心。
我们把它们称为函数式组合。来看一个 compose 函数的例子
var add1 = (value) =>{ return value+1 }; var double = (value) => {return value*2 }; var compose = (a,b) => { return (c) => { return a(b(c)); } } var doubleAndAdd1 = compose(add1,double); doubleAndAdd1(5) // 打印 5 * 2 + 1 = 11
compose 函数返回一个函数,将 b 的结果作为 a 的参数,这里就是将 double 的结果作为 add1 的参数,来实现了函数的组合。
8、 纯函数是数学函数
还记得我们之前的缓存函数吗,假设我们多次调用 double 对象,那么 cache 中就会变成这样
{ 1: 2, 2: 4, 3: 6, 4: 8, 5: 10 }
假设我们设置 double 的输入范围限制为 1 - 5,而且我们已经为这个范围建立的 cache 对象,因此只要参照 cache 就能根据指定输入返回指定输出。也就是一一对应的关系。
那么数学函数的定义是什么呢?
在数学中,函数是一种输入集合和可允许的输出集合之间的关系,具有如下属性:每个输入都精确地关联一个输出。函数的输入称为参数,输出称为值。对于一个给定的函数,所有被允许的输入集合称为该函数的定义域,而被允许的输出集合称为值域。
上面的定义和纯函数完全一致,例如在 double 中,你能找到定义域和值域吗?当然可以!通过这个例子,可以很容易看到数学函数的思想被借鉴到函数式范式的世界
9、 我们要做什么?
我们将通过学习,构建出一个 ES6-Functional 的函数式库,通过构建的过程,我们将理解如何使用 JavaScript 函数,以及如何在日常工作中应用函数式编程。
10、小结
这一节我们只是简单的介绍了函数式编程的概念,以及什么是纯函数,其中最重要的就是引用透明性。然后研究了几个短小的例子,通过例子来加深对函数式编程的理解。接下来我们将一步一步深入了解函数式编程。
위 내용은 함수형 프로그래밍 소개 및 요약(코드 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!