8

我一直在研究为我的团队提出标准化的 Javascript 编码风格。现在大多数资源都推荐涉及闭包的“模块”模式,例如:

var Module = function() { 

    someMethod = function() { /* ... */ };

    return { 
        someMethod: someMethod
    };

}();

并像Module.someMethod();. 这种方法似乎只适用于传统 OOP 上下文中的静态方法,例如用于获取/保存数据的存储库类、用于发出外部请求的服务层等。除非我遗漏了什么,否则模块模式不打算与通常需要传递到服务方法或从服务方法传递到 UI 胶水代码的数据类(想想 DTO)一起使用。

我看到引用的一个共同好处是,您可以使用模块模式在 Javascript 中拥有真正的私有方法和字段,但这也可以通过具有类似于此的“经典”Javascript 风格的静态或实例方法来实现:

myClass = function(param) { 
    // this is completely public
    this.publicProperty = 'Foo';

    // this is completely private
    var privateProp = param;

    // this function can access the private fields
    // AND can be called publicly; best of both?
    this.someMethod = function() { 
        return privateProp;
    };

    // this function is private.  FOR INTERNAL USE ONLY
    function privateMethod() { 
        /* ... */
    };
}

// this method is static and doesn't require an instance
myClass.staticMethod = function() { /* ... */ };

// this method requires an instance and is the "public API"
myClass.prototype.instanceMethod = function() { /* ... */ };

所以我想我的问题是是什么让模块模式比传统风格更好?它有点干净,但这似乎是唯一立即显而易见的好处;事实上,传统风格似乎提供了提供真正封装的能力(类似于 Java 或 C# 等真正的 OOP 语言),而不是简单地返回仅静态方法的集合。

有什么我想念的吗?

4

3 回答 3

2

上面的模块模式毫无意义。你所做的只是使用一个闭包来返回一个带有原型的构造函数。您可以通过以下方式实现相同的目标:

function Module() {};
Module.prototype.whatever = function() {};

var m = new Module();
m.whatever();

实际上,您将保存一个对象(闭包),使其具有相同的输出。

我对模块模式的另一个不满是,如果您将它用于私有封装,您只能将它轻松地用于单例而不是具体类。要创建具有私有数据的具体类,您最终会包装两个关闭器,这会变得很难看。我也同意,当它们可见时,能够调试下划线伪私有属性要容易得多。“如果有人错误地使用你的课程怎么办”的整个概念是没有道理的。制作一个干净的公共 API,记录它,如果人们没有正确地遵循它,那么你的团队中有一个糟糕的程序员。Javascript 中隐藏变量所需的工作量(可以在 Firefox 中使用 eval 发现)不值得使用 JS,即使对于大中型项目也是如此。人们不会窥探您的对象来学习它们,他们会阅读您的文档。如果您的文档很好(使用 JSDoc 的示例),那么他们会坚持使用它,就像我们使用我们需要的每个 3rd 方库一样。我们不会“篡改” jQuery 或 YUI,我们只是信任并使用公共 API,而不关心它在下面使用的方式或内容。

于 2012-08-01T13:14:14.467 回答
2

模块模式也可用于创建原型,请参阅:

var Module = function() { 
  function Module() {};
  Module.prototype.whatever = function() {};
  return Module
}();
var m = new Module();
m.whatever();

正如另一张海报所说,干净的全局命名空间是它的原因。然而,实现这一点的另一种方法是使用 AMD 模式,它也解决了其他问题,如依赖管理。它还将所有内容包装在各种闭包中。这是一个很棒的 AMD 简介, 它代表异步模块定义。

我还建议阅读JavaScript 模式,因为它彻底涵盖了各种模块模式的原因。

于 2012-05-16T19:18:28.300 回答
1

您忘记提及模块模式的另一个好处是,它可以减少全局名称空间中的混乱,即人们说“不要污染全局名称空间”时所指的内容。当然,您可以在经典方法中做到这一点,但似乎在匿名函数之外创建对象会更容易在全局命名空间中创建这些对象。

换句话说,模块模式促进了自包含代码。一个模块通常会将一个对象推送到全局命名空间中,并且与模块的所有交互都通过该对象进行。这就像一个“主要”方法。

全局命名空间中的混乱较少是好的,因为它减少了与其他框架和 javascript 代码冲突的机会。

于 2012-05-16T19:09:31.537 回答