在获得原则之前,首先让您了解一点。
什么是功能编程
功能编程是一种范式,其根源在数学上,主要源于lambda conculus。
它的主要重点是与当务之急的风格相反,主要重点是如何解决。
功能编程的目的是声明性,并将应用视为彼此组成的纯粹功能的结果。
这种编程风格的主要目的是避免共享状态,可变的数据和副作用带来的问题,这些问题是面向对象的编程中的常见位置。
与面向对象的编程相比,功能编程往往更可预测,更易于测试,但对于新启动者来说似乎也很难学习,但功能性编程并不像最初看起来一样困难。
为什么我们需要功能编程?
功能编程和小缺点有一些主要好处:
优点:
- 更可读性,因此可维护性
- 较少的货物,尤其是在并发的情况下
- 关于解决问题的新方法
- (个人奖金)很高兴了解!
缺点:
- 可以有绩效问题
- 在与状态打交道时与与国家打交道时的工作不那么直观
- 对大多数人的不熟悉 +减慢学习过程的数学术语
功能编程往往比面向对象的编程更容易预测,更易于测试。
原则
在更广泛的层面上,主要有6种功能编程原则
- 纯度
- 不变性
- 纪律状态
- 头等舱功能和高阶功能
- 类型系统
- 参考透明度
让我们在下面的详细信息中查看它们。
纯度
- 纯函数是一个函数(代码块),如果传递相同的参数,它总是会返回相同结果。
- 在程序执行过程中,它不取决于任何状态或数据更改。相反,这仅取决于其输入参数。
- 另外,纯函数不会产生任何可观察的副作用,例如网络请求或数据突变等。
- 它没有副作用,例如修改参数或全局变量或输出某物。
- 纯函数是可预测且可靠的。最重要的是,他们只计算结果。调用纯函数的唯一结果是返回值。
让我们在下面查看用于计算GST的示例。
const calculateGST = (productPrice) => {
return productPrice * 0.05;
}
- 平方函数中的计算取决于输入。无论我们将带有相同输入的正方形函数调用多少次,它将始终返回相同的输出。 下面的示例
const sqaureIt= (number) => {
return number * number;
}
不变性
- 不变的数据无法更改其结构或数据。
- 一旦将值分配给某物,该价值就不会更改。
不变性是功能编程的核心。例如,这消除了副作用(例如,本地函数范围之外的任何内容),例如,在功能之外更改其他变量。
- 不变性有助于在整个程序的整个运行时保持状态。
- 它使代码简单,可测试,并且能够在分布式和多线程系统上运行
- 由于功能具有纪律处分,并且不会在功能之外更改其他变量,因此我们不需要查看函数定义之外的代码。
- 当我们使用数据结构时,不变性经常发挥作用。 JavaScript中的许多数组方法直接修改数组。
例如,.pop()
直接从数组的末端删除了一个项目,而.splice()
允许您取一部分数组。
// We are mutating myArr directly
const myArr = [1, 2, 3];
myArr.pop();
// [1, 2]
相反,在功能范式中,我们将复制数组,然后在此过程中删除我们要消除的元素。
// We are copying the array without the last element and storing it to a variable
let myArr = [1, 2, 3];
let myNewArr = myArr.slice(0, 2);
// [1, 2]
console.log(myArr);
纪律处分
- 纪律状态与共享,可变状态相反。
- 共享的可变状态很难保持正确,因为有许多功能可以直接访问该状态。也很难阅读和维护。
- 使用可变状态,我们需要查找使用共享变量的所有功能,以了解逻辑。 - 出于相同的原因很难进行调试。
- 当我们牢记功能编码原则时,您会尽可能避免具有共享的可变状态。
- 当然我们可以有状态,但是您应该保持本地化,这意味着我们的功能内部。这是状态纪律:我们使用状态,但以非常纪律的方式。
共享,可变状态的缺点的一个例子是:
const logElements = (arr) => {
while (arr.length > 0) {
console.log(arr.shift());
}
}
const main = () => {
const arr = ['Node', 'React', 'Javascript', 'Typescript'];
console.log('=== Before sorting ===');
logElements(arr);
arr.sort();
console.log('=== After sorting ===');
logElements(arr);
}
main();
// === Before sorting ===
// "Node"
// "React"
// "Javascript"
// "Typescript"
// === After sorting ===
// undefined
我们可以看到第二个呼叫不会产生任何结果,因为第一个呼叫清空了输入数组,从而突变了应用程序状态产生意外的输出。
为了解决此问题,我们转向不变性和使用副本来保持初始状态透明和不变。
const logElements = (arr) => {
while (arr.length > 0) {
console.log(arr.shift());
}
}
const main = () => {
const arr = ['Node', 'React', 'Javascript', 'Typescript'];
console.log('=== Before sorting ===');
logElements([...arr]); // Change in line
const sorted = [...arr].sort(); // Assign sorted items to another variable
console.log('=== After sorting ===');
logElements([...sorted]); // Change in line
}
main();
// === Before sorting ===
// "Node"
// "React"
// "Javascript"
// "Typescript"
// === After sorting ===
// "Javascript"
// "Node"
// "React"
// "Typescript"
头等舱功能和高阶功能
高阶功能是至少具有以下操作之一的函数:
- 将一个或多个功能作为参数
- 返回功能作为结果
功能编程将功能视为一流的公民。
这意味着函数可以作为参数传递给其他函数,并从其他函数中返回,并存储在数据结构中并分配给变量。
const plusFive = (number) => {
return number + 5;
};
// f is assigned the value of plusFive
let f = plusFive;
plusFive(3); // 8
// Since f has a function value, it can be invoked.
f(9); // 14
高阶函数是将一个或多个函数作为参数或返回函数作为其结果的函数。
类型系统
通过使用类型,我们利用编译器来帮助我们避免在开发过程中可能发生的常见错误和错误。
使用JavaScript,我们可以执行以下操作:
const add = (left, right) => {
return left + right;
}
add(2, 3) // 5
add(2, "3"); // "5"
这很糟糕,因为现在我们收到的意外输出可能被编译器捕获。
让我们查看用打字稿编写的相同代码:
const add = (left: number, right: number): number => {
return left + right;
}
add(2, 3) // 5
add(2, "3"); // error!
在这里,我们可以看到编译器正在采取行动保护我们免受此类基本问题的侵害,当然,使用静态键入的开发方法可能会有更多的可能性,但这应该为您提供了为什么使用它很有用的要点。
>参照透明度
-
参考透明度是一种奇特的说法,如果您要用其返回值替换函数调用,则该程序的行为将与以前一样可预测。
-
参考透明的函数仅依赖于其输入,因此与纯函数和不可分率的概念紧密相符。
-
如果可以将其用相应的值替换而不更改程序的行为,则表达式被认为是透明的。
-
要达到参考透明度,函数必须是纯净的。这在可读性和速度方面具有好处。编译器通常能够优化表现出参考透明度的代码。
const two = () => {
return 2;
}
const four = two() + two(); // 4
// or
const four = two() + 2; // 4
// or
const four = 2 + two(); // 4
// or
const four = 2 + 2; // 4
结论
功能编程为我们提供了一些使我们的代码更可读,可预测和可测试的原则。
这使我们可以拥有较少的错误,更容易入职和通常从我的经验中的代码库的代码。
另外,要通知我的新文章和故事:在Medium上关注我。
订阅我的YouTube Channel关于类似主题的教育内容
您可以在LinkedIn上找到我,因为它是一个适合像我和您这样的人的专业网络。
欢呼!!!