【问题标题】:How can I simulate macros in JavaScript?如何在 JavaScript 中模拟宏?
【发布时间】:2010-09-16 15:37:21
【问题描述】:

我知道 JavaScript 不支持宏(Lisp 风格的),但我想知道是否有人有解决方案来模拟宏?我用谷歌搜索了一下,其中一个解决方案建议使用eval(),但正如他所说,成本会很高。

他们真的不必很花哨。我只想和他们做一些简单的事情。而且它不应该使调试变得更加困难:)

【问题讨论】:

    标签: javascript macros metaprogramming


    【解决方案1】:

    您可以使用parenscript。这将为您提供 Javascript 的宏。

    【讨论】:

    • -1 虽然 parenscript 在 2008 年还可以,但您现在应该真正使用 ClojureScript。
    • 不同的解决方案... Parenscript 是一个相当薄的层,与 ClojureScript 不同。
    • 不仅解决方案不同,语言也不同
    • @CesarCanassa parenscript 是一个 Common Lisp 库,它适用于大多数(可能是所有)主要实现(我自己尝试过)。 Clojurescript 面向更小众的市场,适合不同的受众。
    【解决方案2】:

    Mozilla 的一个库(称为SweetJS)旨在模拟 JavaScript 中的宏。例如,您可以使用 SweetJS 将 function 关键字替换为 def

    【讨论】:

      【解决方案3】:

      现在还可以使用ClojureScript 将clojure 编译为javascript 并以这种方式获取宏。注意 ClojureScript 使用 Google Closure。

      【讨论】:

        【解决方案4】:

        我用 javascript 编写了一个 gameboy 模拟器,并以这种方式模拟 cpu 模拟的宏:

        宏代码(函数返回带有宏代码的字符串):

        function CPU_CP_A(R,C) { // this function simulates the CP instruction, 
          return ''+             // sets CPU flags and stores in CCC the number
          'FZ=(RA=='+R+');'+     // of cpu cycles needed
          'FN=1;'+
          'FC=RA<'+R+';'+
          'FH=(RA&0x0F)<('+R+'&0x0F);'+
          'ICC='+C+';';
        }
        

        使用“宏”,因此代码是“动态”生成的,我们不需要对它进行函数调用或为每个指令编写大量重复的代码......

        OP[0xB8]=new Function(CPU_CP_A('RB',4)); // CP B
        OP[0xB9]=new Function(CPU_CP_A('RC',4)); // CP C
        OP[0xBA]=new Function(CPU_CP_A('RD',4)); // CP D
        OP[0xBB]=new Function(CPU_CP_A('RE',4)); // CP E
        OP[0xBC]=new Function('T1=HL>>8;'+CPU_CP_A('T1',4)); // CP H
        OP[0xBD]=new Function('T1=HL&0xFF;'+CPU_CP_A('T1',4)); // CP L
        OP[0xBE]=new Function('T1=MEM[HL];'+CPU_CP_A('T1',8)); // CP (HL)
        OP[0xBF]=new Function(CPU_CP_A('RA',4)); // CP A
        

        现在我们可以像这样执行模拟代码:

        OP[MEM[PC]](); // MEM is an array of bytes and PC the program counter
        

        希望对你有帮助...

        【讨论】:

        • new Function(string)eval() 上下文,因此具有与eval() 相同的性能特征
        • 我不认为这是真的。它可能是一个评估,但评估只发生一次。一旦它是一个函数,它应该以正常的函数速度执行任意次数。
        • IIRC,过去大多数 JS 引擎都没有优化 Function 对象,这与“普通” JavaScript 代码不同。然而,当我读到这篇文章是几年前的事了,所以我想知道现在普通的 JS 引擎对它们的支持程度如何。尤其是在闭包优化方面付出了所有努力。
        【解决方案5】:
        function unless(condition,body) {
            return 'if(! '+condition.toSource()+'() ) {' + body.toSource()+'(); }';
        }
        
        
        eval(unless( function() {
            return false;
          }, function() {
            alert("OK");
        }));
        

        【讨论】:

        • 不错的主意,但遗憾的是,该解决方案添加了太多的 eval 和 2x 函数定义。虽然尝试 +1。
        • 宏在编译时被扩展,所以我们需要在 JavaScript 中添加编译阶段或者忘记宏。我们只能通过调用 eval() 函数来编译 JavaScript,所以无论如何我们都需要 eval()。
        • 宏是语法糖,用于更简洁和富有表现力的代码。从理论上讲,它们不会增加您可以做或不能做的事情的类型。它们在编译时消耗一次,使运行时成本为零。此处的示例失败:每次都会调用 eval,并且与直接编写等效的 javascript 相比,代码更冗长且不易理解。为了使宏有用,您应该能够使用类似除非('false','alert(“OK”)')这样的语法;
        • @NicolasBousquet 宏使您能够在代码执行之前(以及在编译之前,宏扩展时间)操作代码。如果没有宏,你就无法做到这一点。
        • 最后,宏生成的代码和手写的代码一样强大,但是任何图灵完备的语言都会给你。重要的是他们增加了可以做的事情。
        【解决方案6】:

        LispyScript 是最新的编译成 Javascript 的语言,它支持宏。它具有类似 Lisp 的树语法,但也保持相同的 Javascript 语义。 免责声明:我是LispyScript的作者。

        【讨论】:

        • LispyScript 是同音语言(如 Scheme 和 Common Lisp)吗?
        • LispyScript 是否与 ParenScript 有任何关系?它们看起来和我非常相似,因为它们都是编译成 JavaScript 的 Lisp 方言。 common-lisp.net/project/parenscript
        • @AndersonGreen 我认为 Santosh 声称 LispyScript 类似于 lisp 但不是 lisp 方言。
        • 不再维护?
        • LispyScript 不再维护,不应使用。
        【解决方案7】:

        查看 Linux/Unix/GNU M4 处理器。它是适用于任何语言的通用且功能强大的宏处理器。它特别面向 JavaScript 所属的 Algol 风格的语言。

        【讨论】:

          【解决方案8】:

          Javascript 被解释。 Eval 并不比 Javascript 中的其他任何东西更昂贵。

          【讨论】:

          • 错了!詹姆斯,请阅读这个问题:stackoverflow.com/questions/86513/… 并在做出误导性陈述之前验证您的意见。每次调用 eval 时,必须解析/解释传递给 eval 的字符串!
          • 是的,传递给 eval 的字符串必须在每次调用 eval 时进行解析——但每隔一行 javascript 也必须如此。这就是口译员的工作方式。至于您链接到的答案,他从未提及速度,只是“更容易阅读并且潜在的错误更少”
          • 我承认这可能是 2000 年左右浏览器中的 Javascript 的情况,但今天对纯 Javascript 代码(即非 eval'd)进行了严格的优化,而这只会继续。任何语言的字符串中的代码也无法在任何地方进行优化。
          • Ash,我相信 James 试图说明的一点是,对于一次性交易,eval 的工作速度与文字 JavaScript 一样快,因为解释器正在执行任何一种方式同样的事情 - 获取一个字符串并执行它。你认为文字 JavaScript 是什么?它是 HTML 文件中的字符串。
          猜你喜欢
          • 2015-09-19
          • 1970-01-01
          • 2015-09-07
          • 1970-01-01
          • 2014-07-14
          • 1970-01-01
          • 1970-01-01
          • 2014-08-20
          • 1970-01-01
          相关资源
          最近更新 更多