我想指出这篇文章中的许多错误,仅仅是因为它是…

我想指出本文中的许多错误,只是因为它错误地表示了OOP和FP。

OOP不一定仅用于封装。 OOP的基础是继承。 从理论上讲,它允许通过继承将方法从父级传递给子级,从理论上讲,它允许大量的代码重用。 但是,它有一些大问题……

我认为缺乏可重用性的是面向对象的语言,而不是功能语言。 因为面向对象语言的问题是他们拥有了它们所伴随的所有隐式环境。 您想要香蕉,但是得到的是一只大猩猩,拿着香蕉和整个丛林。

如果您具有透明的参照代码,并且具有纯函数(所有数据都包含在其输入参数中,并且所有内容都消失并且不留任何状态),那么它将具有非常好的可重用性。

〜Erlang的创建者Joe Armstrong谈软件的可重用性。

当然,幸运的是,在JS中我们没有经典的OOP继承。 我们有原型继承。 这意味着我们实际上并没有引入整个森林,而只是引用了。

在JS中,我们可以像使用JS“类”一样轻松地用FP封装逻辑。 JS模块系统允许完全封装。 我可以编写FP样式的代码,将我的所有逻辑封装为具有逻辑结构和关注点分离的离散部分。 我可以在模块中编写私有函数,也可以在从模块中导出它们公开的公共函数中编写私有函数。 我可以将其他一些模块与对象分解所需的功能放在一起。

声称FP导致“意大利面条式代码”对我来说是由于对FP范例的浅浅或不正确的理解,以及代码组织和应用程序体系结构的通用JS最佳实践,无论您选择使用类还是纯编写职能。

FP的核心基础是我们可以期望从相同的输入获得相同的回报。 我们不会在函数外部修改或绑定任何全局状态,也不会在函数内部调用外部函数。 它与lambda演算有关,因为纯函数具有许多令人敬畏的属性,例如能够将它们组合在一起,并易于根据输入预测输出。

纯函数易于测试,并且易于调试。 他们有一个干净的界面。 从给定的输入我们可以确定给定的输出。 不断引用“ this”的复杂对象的使用没有这种简单性,并且可能导致难以发现错误和难以测试代码。 在FP范式的限制内工作将帮助您非常清楚所编写的每个函数的副作用,并迫使您对构造应用程序的基本方式以及数据如何通过该应用程序进行推理。 如果仅是为了避免副作用,那么它使您成为更好的程序员。

当然,我们永远无法完全避免副作用,例如DOM操作,对API的异步调用,事件挂钩等。但是,我们可以控制它们,隔离它们并使它们明确,以确保易于阅读的代码,并且我们知道并可以确定应用程序中最有可能爬虫的位置。我们可以隔离副作用,并在其周围放一些黄色胶带,以向我们自己和其他人发出警告,指出该区域很容易出现漏洞和很难测试。

这里要做的另一个区别是有FP和OOP,但也有命令式和声明式。 我们可以用两种方式在OOP中编写一些函数。 我们可以使用for循环和命令式,也可以使用HOF(例如Map或Reduce)并进行声明式。 声明式编码的优点是易于理解,并且易于理解,并且更适合我们经常考虑使用计算机的方式-我们声明要完成的工作,然后计算机执行此操作。 它所做的硬业务逻辑被抽象出来。

FP仅由于其结构的性质而使其具有声明性样式。 我们抽象出较低层的业务逻辑,通过纯函数封装复杂性,然后通过这些纯函数而不是以声明的方式与代码进行交互。 在内部使用for循环编写自己的map函数并传递回调函数是了解这种封装的好处的好方法:

  //当我们封装命令式逻辑时,它更易于阅读, 
//了解并重用。
  const map =(arr,callback)=> { 
const newArr = [];
  for(let i = 0; i <= arr.length-1; i ++){ 
newArr.push(callack(arr [i],i,arr))
}
 返回newArr; 
}

FP对其方法至关重要的另一个概念是功能是一流的功能。 我可以将函数传递给其他函数,也可以从函数返回函数,甚至可以使返回函数的函数返回函数。 这意味着我可以创建一个其他功能的工厂功能。 这允许大量代码重用。 我可以使一个函数以要添加的数量作为参数,而不是一堆都将不同数字添加到给定输入的函数,然后生成一个函数来实现。 这导致了功能异常灵活的系统,该系统不仅可以轻松重用,而且可以组合起来创建全新的功能。 举个例子:

  //带数字 
const add =(a,b)=> a + b;
const乘法(a,b)=> a * b;
 乘法(3,加(2,4)); 
  //带字符串 
  const toUppercase = str => str.toUppercase(); 
const exclamation = str =>`$ {str}!`;
const reverse = str => str.split('')。reverse()。join('');
  //我们可以将这些“组合”在一起以获得一个新函数 
//以一种独特的方式组合它们,尽管我不会介绍
// compose在这里有效,但它结合了功能以创建新功能
  const shout = compose(toUppercase,感叹号); 
const shoutReverse = compose(shout,reverse);
  shoutReverse(“ hello”) 
// =>“!OLLEH”

从较小的函数组成函数的能力仅仅是这些函数是纯函数的结果。 有了预期的输出,我可以将该输出链接到另一个输入。 这就是让我们做如此惊人的排列将数组方法链接在一起的方法,例如.map()。filter()等。

FP很难学习。 它需要您的思维和编程风格。 对于人们来说,很难学习围绕一流功能的想法。 我们不会以不同的方式考虑匿名回调函数,而且我经常看到我的学生将一个函数放在一个匿名回调中,然后只是传递一个参数,这都是因为他们不相信可以在函数中传递该函数。无需调用:

  //这是许多初级甚至中级编码员的东西 
//仍然可以。 他们使用匿名函数传递参数
//到函数。 考虑到这是多余的
//发挥头等公民的作用
  const format = response => response.toJson(); 
fetch('/ myData')
.then(response => {
返回格式(响应)
})
  //当您可以这样做时 
fetch('/ myData')
.then(格式)

本文所代表的内容实际上并不是对FP或其核心概念甚至OOP的正确理解。 存在大量的过度简化,但这两个主题都没有太大的道理。

花些时间按照自己的条件学习FP,不要将其与OOP进行比较。 为此,请花一些时间来学习为什么JS不是经典的继承OOP,以及为什么它如此出色。 还知道我们不需要类来封装我们的逻辑或应用程序。 这不是OOP的主要目的。 OOP主要围绕继承和代码重用,以及以某种方式用“对象”和“继承”对事物建模的想法更接近我们“自然”地思考世界的想法。

OOP和FP最近成为开发人员的流行语。 人们逐渐熟悉了不同的范例,这很高兴,但是这对概念产生了很大的损害,让人们仅靠流行的文章来理解这些文章,而这些文章似乎更多地是在引起轰动,并用广泛的陈述来说明这些事物。深入了解和比较这两种范式。 这很适合花时间学习和正确学习。 Javascript是一种很棒的语言,因为我们可以结合两种范式中的许多技术,并且可以通过了解两者的优缺点并以平衡的方式使用它们来成为更好的程序员。

最后,目标是管理复杂性并创建有意义的抽象,使我们的代码易于阅读和推理,易​​于维护和易于测试。 不要被流行语和简单化的概念所抛弃。 干净的代码很难,而简单的代码通常需要最大的才能来编写。