如何编写一个基于函数式编程的JavaScript应用程序?

我一直在使用node.js一段时间的聊天应用程序(我知道,非常原创,但我觉得这将是一个很好的学习项目)。 Underscore.js提供了很多有趣的函数式编程概念,所以我想了解一下JavaScript中的函数式程序是如何设置的。

从我对函数式编程的理解(这可能是错误的),整个想法是避免副作用,这些副作用基本上具有更新函数之外的另一个variables的function,

var external; function foo() { external = 'bar'; } foo(); 

会造成副作用,对吗? 所以一般来说,你要避免在全球范围内的干扰variables。

好的,那么当你处理对象时又是如何工作的呢? 例如,很多时候,我将有一个构造函数和一个初始化对象的init方法,如下所示:

 var Foo = function(initVars) { this.init(initVars); } Foo.prototype.init = function(initVars) { this.bar1 = initVars['bar1']; this.bar2 = initVars['bar2']; //.... } var myFoo = new Foo({'bar1': '1', 'bar2': '2'}); 

所以我的init方法有意造成副作用,但是如何处理同样的情况呢?

另外,如果任何人都可以指向我的程序的Python或JavaScript源代码,尽可能的function,这也是非常感激。 我觉得我接近“得到它”,但我不是那里。 主要是我感兴趣的是函数式编程如何与传统的OOP类概念一起工作(或者,如果是这种情况,就不要这样做)。

你应该阅读这个问题:

Javascript作为一种function性语言

有很多有用的链接,包括:

  • 使用函数式编程技术来编写优雅的JavaScript
  • 小JavaScripter
  • 高阶JavaScript
  • 雄辩的JavaScript,第6章:函数式编程

现在,我的意见。 很多人误解了JavaScript ,可能是因为它的语法看起来像大多数其他编程语言(Lisp / Haskell / OCaml看起来完全不同)。 JavaScript 不是面向对象的,它实际上是一个基于原型的语言 。 它没有类或古典inheritance,所以不应该与Java或C ++进行比较。

JavaScript可以比Lisp更好; 它具有封闭性和一stream的function。 使用它们,您可以创build其他function性编程技术,如部分应用程序 (柯里化)。

我们来看一个例子(使用node.js中的sys.puts ):

 var external; function foo() { external = Math.random() * 1000; } foo(); sys.puts(external); 

为了摆脱全球性的副作用,我们可以把它封闭起来:

 (function() { var external; function foo() { external = Math.random() * 1000; } foo(); sys.puts(external); })(); 

请注意,我们实际上不能在范围之外对externalexternal做任何事情。 它们完全被封闭,不可触摸。

现在,摆脱external的副作用:

 (function() { function foo() { return Math.random() * 1000; } sys.puts(foo()); })(); 

最后,这个例子并不是纯粹的function,因为它不可能 。 使用随机数从全局状态读取(获取种子)并打印到控制台是一个副作用。

我还想指出的是,将函数式编程与对象混合是非常好的。 以此为例:

 var Square = function(x, y, w, h) { this.x = x; this.y = y; this.w = w; this.h = h; }; function getArea(square) { return square.w * square.h; } function sum(values) { var total = 0; values.forEach(function(value) { total += value; }); return total; } sys.puts(sum([new Square(0, 0, 10, 10), new Square(5, 2, 30, 50), new Square(100, 40, 20, 19)].map(function(square) { return getArea(square); }))); 

正如你所看到的,使用函数式语言中的对象可以很好。 一些Lisp甚至有一些东西叫做属性列表,可以被看作是对象。

在function风格中使用对象的真正诀窍是确保您不依赖于它们的副作用,而是将它们视为不可变的。 一个简单的方法是每当你想改变一个属性,只需创build一个新的对象与新的细节,并通过一个,而不是(这是在Clojure和Haskell中经常使用的方法)。

我坚信function方面可以在JavaScript中非常有用,但最终,你应该使用任何使代码更易读,适合你的东西。

你必须明白,函数式编程和面向对象编程有些相互矛盾。 无论是纯粹的function还是纯粹的面向对象都是不可能的。

函数式编程都是关于无状态计算的。 面向对象编程都是关于状态转换的。 (使这个不合适,希望不会太差)

JavaScript是更多的面向对象比function。 这意味着,如果你想以纯粹的function性风格进行编程,就必须放弃大部分的语言。 具体来说,所有的对象定位部分

如果你愿意更务实一点,那么你可以使用纯粹的function性世界的一些灵感。

我尝试遵守以下规则:

执行计算的函数不应该改变状态。 而改变状态的函数不应该执行计算。 而且,改变状态的函数应该尽可能地改变状态。 目标是拥有许多只能做一件事的小function。 那么,如果你需要做任何事情,你可以编写一些小function来做你所需要的。

遵循这些规则有许多好处:

  1. 易于重用。 function越长越复杂,function越专业,因此可以重复使用的可能性就越小。 相反的意思是更短的函数往往更通用,因此更容易重用。

  2. 代码的可靠性。 如果代码的复杂性较低,则更容易推断代码的正确性。

  3. 当他们只做一件事情时,更容易testingfunction。 这样就可以减less特殊情况下的testing。

更新:

合并意见。

更新2:

增加了一些有用的链接

我认为, http://documentcloud.github.com/underscore/应该很适合你的需要 – 它提供了function性编程最重要的高阶函数,并没有DOM操作的客户端函数,你不要不需要服务器端。 虽然我没有经验。

作为一个方面的说明:恕我直言,function编程的主要特点是参考函数的透明度 – 函数结果只取决于其参数 – 函数不依赖于其他对象的变化,除了结果值没有引入任何变化。 它可以很容易地推断程序的正确性,对于实现可预测的multithreading(如果相关的话)非常有价值。 虽然JavaScript不是FP的赌注语言,但我认为不可变的数据结构在性能上非常昂贵。

所以有两点需要指出,

  1. 在你的第一个例子中,你的variables不会泄漏到全局区域,并且是它应该完成的方式,尽量不要在不声明variables的情况下使用variables,即test ='data'会导致数据泄露到全局区域。

  2. 你的第二个例子也是正确的,bar1和bar2只会在Foo对象上声明。

需要注意的是尽量不要过度使用原型,因为它适用于你创build的每一个对象,这可能是非常耗费内存的,取决于对象的复杂程度。

如果您正在寻找应用程序开发框架,请查看ExtJs 。 就我个人而言,我认为它完全适合你正在试图发展的模式。 请记住,在获得大量投资之前,他们的许可模式是如何工作的。