如何创建一个小型Javascript扩展语言

How to create a small Javascript extension language?

本文关键字:小型 Javascript 扩展 语言 一个 何创建 创建      更新时间:2023-09-26

我最近重构了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.x等。所有内容也可以使用APP.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。

您可能想要了解的内容:

  • 水仙:https://github.com/mozilla/narcissus/
  • Traceur:http://code.google.com/p/traceur-compiler/
  • 反射.js:https://github.com/zaach/reflect.js
  • http://www.mascaraengine.com/doc/languagewalk
  • https://github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS

还有一个关于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
  }
})();

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

然而,由于你把所有事情都"公开"了,它就没有那么有用了。你可以这样做(包括测试代码):

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工具等)也可以用作示例。