JavaScript模块模式差异

时间:2016-03-07 19:07:17

标签: javascript oop design-patterns module

我试图围绕不同的模块模式倾向。我看到了编写这些模块和公开数据的不同方法。

我期待有关优缺点的信息,这里没有描述的更好的模式,每个用例。

A)包含在自调用函数中的对象文字,使用init方法启动: (source)

(function() {

var MyModule = {
  settings: {
    someProperty: 'value';
  }

  init: function() {
    someMethod();
  }

  someMethod: function() {
    // ...
  }
};

MyModule.init();
})();

This是我构建的简单“Tweet This”实用程序的示例。我正确使用这种模式吗?到目前为止,这是我在写作方面的唯一经验。

B)模块作为命名空间自调用匿名函数: (source)

var MyModule = (function () {
  var MyObj = {}

  function privateMethod() {
    // ...
  }

  MyObj.someProperty = 1;
  MyObj.moduleMethod = function () {
    // ...
  };

  return MyObj;
}());

以前的风格是否有任何优点/缺点?此外,在这里使用对象文字符号而不是示例中的点语法会有什么影响?对象文字似乎更简洁,更容易,但我并不是真的知道每个用户的正确用例?

C)模块作为命名空间自动调用匿名函数,但仅通过return块公开所需结果: (source)

var MyModule = (function() {
  var myPrivateVar, myPrivateMethod;

  myPrivateVar = 0;

  myPrivateMethod = function(foo) {
    console.log(foo);
  };

  return {
    myPublicVar: "foo",

    myPublicFunction: function(bar) {
      myPrivateVar++;
      myPrivateMethod(bar);
    }
  };

})();

与之前的样式类似,但不是使用它的所有属性/方法公开整个对象,而是通过return语句公开特定的数据位。

D)模块作为包含在自调用匿名函数中的函数,嵌套函数充当方法。该模块通过window对象公开,然后通过new关键字构建:(source)

(function(window, undefined) {

  function MyModule() {

    this.myMethod = function myMethod() {
      // ...
    };

    this.myOtherMethod = function myOtherMethod() {
      // ...
    };

  }

  window.MyModule = MyModule;

})(window);

var myModule = new MyModule();
myModule.myMethod();
myModule.myOtherMethod();

我假设这种模式的优势在于模块是一个“模板”,其中多个实体可能需要存在于应用程序中。一个好的用例的具体例子吗?

1 个答案:

答案 0 :(得分:2)

所有这些都以略微不同的方式使用相同的模式。

A)包含在自调用函数中的对象文字,使用init方法启动:

如果您不打算允许其他人访问一大块代码,那么这很好。你甚至不必拥有init功能。将代码包装在IIFE(立即调用的函数表达式)中可以防止全局命名空间污染并允许使用" private"变量。在我看来,这只是一个好习惯,而不是一个模块。

B)模块作为命名空间自调用匿名函数:

这是人们在谈论模块模式时的意思。它为您提供私有变量和函数,然后通过公共接口公开它们。在您的示例中,恰好将该接口称为MyObj

C)模块作为命名空间自动调用匿名函数,但仅通过return块公开所需结果:

这实际上与 B 完全相同。唯一的区别是界面上的方法不能像 B 那样直接引用界面本身。例如:

MyObj.methodA = function() {
  return MyObj.methodB();
};

这将与上一个示例一起使用,因为您有一个名称来引用它,但仅在您期望使用除返回对象之外的任何其他内容作为执行上下文调用公共方法时才有用。即,setTimeout(MyModule.methodA)(将使用全局上下文调用,因此this.methodB()将无法正常工作。

D)模块作为包含在自调用匿名函数中的函数,嵌套函数充当方法。该模块通过window对象公开,然后通过new关键字构建:

与之前的2相同,除了2个小的差异。 window作为参数传递,因为从历史上看,访问局部变量比全局变量更快,因为引擎不必爬上范围链。但是,如今大多数JS引擎都会优化访问window,因为它是常见的和已知的对象。同样,undefined作为参数给出,不作为参数传递。这可确保您拥有正确的undefined值。这背后的原因是从技术上讲,您可以在非严格模式下为undefined分配任何值。这意味着某些第三方可能会写undefined = true;并且突然所有undefined项检查都失败了。

另一个区别是你正在返回一个函数而不是一个对象。这背后的好处是你可以拥有在每个对象实例中共享的私有变量,以及每个实例的私有变量。例如:

var count = 0;
function MyObject(id) {
  var myID = id;
  count++;

  // Private ID
  this.getID = function() {
    return myID;
  };

  // Number of instances that have been created
  this.getCount = function() {
    return count;
  };
}

这样做的缺点是你没有将方法附加到原型上。这意味着JS引擎必须为对象的每个单个实例创建一个全新的函数。如果它在原型上,则所有实例将共享相同的功能,但不能具有单独的私有变量。