8

我最近重构了我的 JS 代码并偶然发现了这种模式:

APP = (function() {
  var x,y,z;
  function foo() {}
  function bar() {}
  return {x:x, y:y, z:z, foo:foo: bar:bar};
})();

这样做的好处是它创建了非全局变量,函数可以访问APP. 所以无需输入,等就APP.foo可以访问x, y, z, 和 bar 。也可以使用,等全局访问所有内容。您还可以嵌套它们:APP.bar()APP.xAPP.bar()APP.x

APP = (function() {
  var x,y,z;
  function foo() {}
  function bar() {}

  var WIDGETS = (function() {
    var a,b,c;
    function hello() {}
    function world() {}
    return {a:a, b:b, c:c, hello:hello, world:world};
  })();

  return {x:x, y:y, z:z, foo:foo: bar:bar, WIDGETS:WIDGETS};
})();

因此WIDGETS可以访问 中的变量APP,但反之亦然(APP.WIDGETS.hello可以使用foo(),但APP.foo必须使用WIDGETS.hello())。

我尝试使用 ERB(我在 Rails 上)创建这种模式,但结果很混乱。所以我正在考虑为此编写一个小的源到源编译器——比如 CoffeeScript(具有 SASS 的最小差异/扩展语言哲学),它只是将一些函数编译为替代 javascript。

我只是想要一个速记。

例如,这将编译为我上面的第二个代码块:

//NAMESPACE is a magical function I compile down to the long version in the second code block
APP = NAMESPACE(function() {
  var x,y,z;
  function foo() {}
  function bar() {}

  var WIDGETS = NAMESPACE(function() {
    var a,b,c;
    function hello() {}
    function world() {}
    //**notice the missing return statement that I don't need to manage and map to my variables**
  });
  //**notice the missing return statement that I don't need to manage and map to my variables**
});

简单而小巧——这样您就不需要跟踪变量了。也想像这样分离命名空间(所以我可以将它拆分为多个文件):

APP = NAMESPACE(function() {
  var x,y,z;
  function foo() {}
  function bar() {}
  //**notice the missing return statement that I don't need to manage and map to my variables**
});
APP = NAMESPACE(function() {
  var WIDGETS = NAMESPACE(function() {
    var a,b,c;
    function hello() {}
    function world() {}
    //**notice the missing return statement that I don't need to manage and map to my variables**
  });
});

关于如何做到这一点的任何想法?我不确定一切,但我认为如果存在的话,我会更喜欢 Javascript。

4

2 回答 2

1

您可能想要查看的内容:

还有一个关于 EcmaScript 6 中的模块系统的提案,将来可能会可用:http ://wiki.ecmascript.org/doku.php?id=harmony:modules

现在,如果目标只是打字foo()而不是APP.foo()那么我认为创建 javascript 的语言超集有点牵强...

如果您使用 CoffeeScript 导出变量,则不那么冗长:

APP = do ->
  [x,y,z] = []
  foo = ->
  bar = ->

  WIDGETS = do ->
    [a,b,c] = []
    hello = ->
    world = ->
    { a, b, c, hello, world }

  { x, y, z, foo, bar, WIDGETS }

实际上,您很少导出每个变量,实际上您中的一些变量是“私有的”。您还可以在对象本身内部定义函数:

APP = (function() {
  var x,y,z;

  var WIDGETS = (function() {
    var a,b,c;
    return {
      hello: function hello(){},
      world: function world(){}
    }

  })();

  return {
    foo: function foo(){},
    bar: function bar(){},
    widgets: WIDGETS
  }

})();
于 2012-07-14T23:45:27.457 回答
0

您所描述的是通常称为“模块模式”的内容。这很好,因为您可以定义“隐藏”且无法访问的内部方法和变量。它也不会污染全局命名空间。您可以在此处阅读更多相关信息(我相信这是有关该技术的第一篇文章。)也可以在此处此处

但是,由于您将所有内容都“公开”,因此它没有那么有用。你可以这样做(包括测试代码):

APP = function (me) {
      me.x = 0;
      me.y = 0;
      me.z = 0;
      me.foo = function () { alert(me.x); },
      me.bar = function () {};

      WIDGETS = function (me2) {
        me2.a = 0;
        me2.b = 0;
        me2.c = 0;
        me2.hello = function () {};
        me2.world = function () {};
        return me2;
      }({});

      return me;
   }({});

APP.x = 1;
APP.foo();

你可以用更少的语法得到同样的效果。

http://jsfiddle.net/ZwCUh/


作为旁注,有一些方法可以在没有编译器的情况下编写代码,这些方法可以让您通过原型接近您正在寻找的内容。一个很好的例子是 jQueryUI 的源代码。我确信其他库(原型、moo 工具等)也可以用作示例。

于 2012-07-14T18:53:38.920 回答