如何构建基于函数式编程的JavaScript应用程序?

use*_*715 29 javascript functional-programming serverside-javascript node.js underscore.js

我已经在聊天应用程序上使用node.js了一段时间(我知道,非常原创,但我认为这是一个很好的学习项目).Underscore.js提供了许多看起来很有趣的函数式编程概念,所以我想了解如何设置JavaScript中的函数式程序.

根据我对函数式编程的理解(这可能是错误的),整个想法是避免副作用,这些副作用基本上都有一个函数来更新函数之外的另一个变量,所以像

var external;
function foo() {
   external = 'bar';
}
foo();
Run Code Online (Sandbox Code Playgroud)

会产生副作用,对吗?因此,作为一般规则,您希望避免在全局范围内扰乱变量.

好的,那么当你处理对象时它是如何工作的呢?例如,很多时候,我将有一个构造函数和初始化对象的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'});
Run Code Online (Sandbox Code Playgroud)

所以我的init方法是故意造成副作用,但是处理相同情况的功能方法是什么?

此外,如果有人可以指向我尝试尽可能功能的程序的Python或JavaScript源代码,那也将非常感激.我觉得我接近"得到它",但我只是不在那里.主要是我对函数式编程如何与传统的OOP类概念一起工作感兴趣(或者如果出现这种情况的话,可以将其用于不同的东西).

Bri*_*nna 30

你应该读这个问题:

Javascript作为一种功能语言

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

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

与Lisp相比,JavaScript可以更好; 它有闭包和一流的功能.使用它们可以创建其他函数式编程技术,例如部分应用程序(currying).

让我们举个例子(使用sys.putsnode.js):

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

sys.puts(external);
Run Code Online (Sandbox Code Playgroud)

为了消除全局副作用,我们可以将其包装在一个闭包中:

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

    sys.puts(external);
})();
Run Code Online (Sandbox Code Playgroud)

请注意,我们实际上无法在范围之外externalfoo之外执行任何操作.他们完全被自己的封闭所包裹,不可触碰.

现在,摆脱external副作用:

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

    sys.puts(foo());
})();
Run Code Online (Sandbox Code Playgroud)

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

我还想指出,将函数式编程与对象混合完全没问题.以此为例:

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);
})));
Run Code Online (Sandbox Code Playgroud)

如您所见,使用函数式语言中的对象可以很好.有些Lisps甚至还有一些称为属性列表的东西,它们可以被认为是对象.

在功能样式中使用对象的真正技巧是确保您不依赖于它们的副作用,而是将它们视为不可变的.一种简单的方法是,只要您想要更改属性,只需使用新的详细信息创建一个对象并将其传递给另一个(这是Clojure和Haskell中经常使用的方法).

我坚信功能方面在JavaScript中非常有用,但最终,你应该使用任何使代码更具可读性和适合你的方法.

  • @Brian你在上面的例子中所谓的_object_并不是一个对象,因为它是一个结构或一个元组,我的意思是它纯粹是一个_data_类型.对象(如在面向对象中)是数据_和方法_的封装,它们的特点是它们可以改变你对它们称为方法的状态.现在,无论你选择什么称呼它,它都是一个渗透JavaScript的概念,如果你选择追求纯粹的功能性风格,你将不得不这样做. (2认同)

Kap*_*old 5

您必须了解函数式编程和面向对象编程在某种程度上是相互对立的.它既不可能是纯功能的,也不是纯粹的面向对象的.

功能编程就是无状态计算.面向对象编程完全是关于状态转换.(Paraphasing ,希望不会太严重)

JavaScript更面向对象而不是功能.这意味着如果你想以纯粹的功能性风格进行编程,你必须放弃大部分语言.特别是所有面向对象的部分.

如果你愿意更加务实,那么你可以使用纯粹功能性世界的一些灵感.

我尝试遵守以下规则:

执行计算的函数不应改变状态.并且改变状态的函数不应该执行计算.此外,改变状态的函数应该尽可能少地改变状态.目标是拥有许多只做一件事的小功能.然后,如果你需要做大事,你可以编写一些小函数来完成你需要的工作.

遵循以下规则可以获得许多好处:

  1. 易于重用.函数越长越复杂,它也越专业化,因此它可以重用的可能性越小.相反的含义是,较短的函数往往更通用,因此更容易重用.

  2. 代码的可靠性.如果代码不太复杂,则更容易推理代码的正确性.

  3. 当它们只做一件事时,更容易测试功能.这样就可以减少要测试的特殊情况.

更新:

来自评论的建议.

更新2:

添加了一些有用的链接

  • 我不同意.JavaScript实际上比面向对象更具功能性.它有闭包,一流的功能,缺少类和继承.从语法上讲,它更像是Java而不是Lisp,但实际上与后者的共同点更多. (3认同)