我一直在和 node.js 在聊天应用程序上有一段时间(我知道,非常原始,但我认为这是一个很好的学习项目)。 下划线 提供了许多看起来很有趣的功能编程概念,因此我想了解如何设置JavaScript中的功能程序。

从我对功能编程的理解(可能是错误的)来看,整个想法是避免副作用,基本上,它具有一个函数,该函数更新了功能之外的另一个变量,因此类似的东西

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

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

好的,当您处理对象时,这如何工作?例如,很多时候,我都会有一个构造函数和一个初始化对象的启动方法,例如:

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'});

因此,我的初始方法有意造成副作用,但是如何处理相同情况的功能方式呢?

另外,如果有人可以向我指出程序的Python或JavaScript源代码,该程序试图尽可能发挥功能,这也将不胜感激。我觉得自己接近“获得”,但我还不到那儿。主要是我对功能编程如何与传统OOP类概念合作(如果是这种情况,也可以用它的不同之处)感兴趣。

有帮助吗?

解决方案

您应该阅读此问题:

JavaScript作为功能语言

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

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

与LISP相比,JavaScript可以更好。它具有关闭和一流的功能。使用它们,您可以创建其他功能编程技术,例如 部分申请 (咖喱)。

让我们举个例子(使用 sys.puts 来自node.js):

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);
})();

请注意,我们实际上不能做任何事情 external 或者 foo 在范围外。他们完全包裹着自己的关闭,无法触及。

现在,摆脱 external 副作用:

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

    sys.puts(foo());
})();

最后,示例不是纯粹的功能 不能 是。使用从全局状态(获取种子)读取的随机数读取并向控制台打印是副作用。

我还想指出,将功能编程与对象混合完全可以。以此为例:

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);
})));

如您所见,使用功能语言中的对象可以很好。有些Lisps甚至具有称为属性列表的事物,可以将其视为对象。

使用功能样式使用对象的真正技巧是确保您不依赖它们的副作用,而是将其视为不可变的。一个简单的方法是每当您想更改属性时,只需创建一个 新的 对象具有新的细节并传递该细节(这是Clojure和Haskell中经常使用的方法)。

我坚信功能方面在JavaScript中可能非常有用,但是最终,您应该使用使代码更可读和对您有用的任何内容。

其他提示

您必须了解,功能编程和面向对象的编程与彼此有些相反。两者都不可能 纯粹的功能 纯粹是面向对象的。

功能编程 全部关于无状态计算。 面向对象的编程 都是关于国家过渡的。 (解释 . 。希望不要太糟糕)

JavaScript比其功能更面向对象。这意味着,如果您想以纯粹的功能风格进行编程,则必须放弃该语言的大部分。特别是所有对象的正向零件。

如果您愿意对此更加务实,那么您可以使用纯粹的功能世界的一些灵感。

我试图遵守以下规则:

执行计算的函数不应改变状态。改变状态的功能不应执行计算。同样,改变状态的功能应改变状态尽可能少。目的是拥有许多只做一件事的小功能。然后,如果您需要做任何大事,您会组成一堆小功能来完成您需要的事情。

遵循以下规则有很多好处:

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

  2. 代码的可靠性。如果代码的正确性不那么复杂,则更容易理解。

  3. 当它们仅执行一件事时,测试功能更容易。这样一来,要测试的特殊情况较少。

更新:

并入评论中的建议。

更新2:

添加了一些有用的链接。

我认为, http://documentcloud.github.com/underscore/ 应该非常适合您的需求 - 它为功能编程提供了最重要的高阶功能,并且没有用于服务器端不需要的DOM操作的客户端功能。虽然我没有经验。

旁注:恕我直言,功能编程的主要特征是 参考透明度 函数 - 函数结果仅取决于其参数 - 函数不取决于其他对象的更改,并且除了其结果值外不会引入任何更改。它可以轻松理解程序的正确性,并且对于实施可预测的多线程(如果相关)非常有价值。尽管JavaScript不是FP的BET语言 - 我希望不变的数据结构在性能方面非常昂贵。

所以2件事要指出,

  1. 在您的第一个示例中,您的变量不会泄漏到全局区域,而应该这样做的方式,请不要在不声明它们的情况下使用变量,即测试='数据'会导致数据泄漏到全局区域。

  2. 您的第二个示例也是正确的,BAR1和BAR2仅在FOO对象上声明。

要记住的事情尽量不要过度使用原型,因为它适用于您创建的每个对象,这可能是非常密集的,具体取决于对象的复杂程度。

如果您正在寻找应用程序开发框架,请查看 Extjs. 。我个人认为这将完全适合您试图发展的模型。请记住,在投入大量投资之前,他们的许可模型如何工作。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top