JavaScript-递归调用部分应用函数

JavaScript-递归调用部分应用函数,javascript,functional-programming,Javascript,Functional Programming,我正在用JavaScript(Node.js)编写一个文件处理器。简化的伪代码如下。对于文件中的每一行,它都打印输出,如果该行是一个include指示符,它将递归地处理包含的文件 function fileProcessor (file) { // read lines from file lines.forEach( function (line) { // #1 - include processor: if line matches "#include includ

我正在用JavaScript(Node.js)编写一个文件处理器。简化的伪代码如下。对于文件中的每一行,它都打印输出,如果该行是一个include指示符,它将递归地处理包含的文件

function fileProcessor (file) {
  // read lines from file
  lines.forEach( function (line) {
    // #1 - include processor:
    if line matches "#include includefile"
      fileProcessor(includefile);
    // #2 - output processor:
    // write line to output
  });
}
下一步我想通过解耦文件处理器和行处理器来改进它的设计。我熟悉OO,它应该看起来像下面的类图。但现在我想用FP的方式试试

定义一个函数,返回应用哪些行处理器的fileProcessor

var fileProcessorGen = function (lineProcessors) {
  return function (file) {
    // read lines from file
    lines.forEach( function (line) {
      lineProcessors.forEach( function (processor) {
        processor.call(this, line);
      });
    });
  };
};

我的目的是实现关注点分离。在这个例子中,只有两个行处理器,但实际上会有更多。调用者会根据自己的需要选择一些线路处理器。所以我不会把它们硬编码到文件处理器或任何行处理器中

var fileProcessor = fileProcessorGen([includeProcessor, outputProcessor]);
现在我的问题是如何在include处理器中调用fileProcessor(部分应用程序)

function includeProcessor(line) {
  if line matches "#include includefile"
    fileProcessor(includefile);  // <--- how to get fileProcessor ?
};

function outputProcessor(line) {
  // write line to output
}
函数includeProcessor(行){
如果行匹配“#包含includefile”

fileProcessor(includefile);//您只需给匿名函数一个名称,然后就可以在函数范围内通过该标识符引用它,而不管您将该函数分配给哪个标识符。(我几乎总是建议给函数命名,甚至是函数表达式。不仅仅是为了能够引用它们,而且为了更容易读取堆栈跟踪)

但是您当然应该意识到,当前的解决方案效率极低,因为它每次调用时都会创建全新的函数集,如果您只声明一次函数并让它们相互调用,则可以使这一过程变得更加简单和高效

function fileProcessor ( file ) {
    //split those lines
    lines.forEach( lineProcessor );
}

function lineProcessor ( line ) {
    if line matches "#include includefile"
        fileProcessor( includefile );
    else
        outputProcessor( line );
}

function outputProcessor ( line ) {
   //...
}
如果您想支持多个指令,只需在hashmap(也称为“一个javascript对象”)中按名称查找它们,或者如果名称不在映射中,则抛出一个错误。(ES6中还有实际的
map
数据类型,您也可以用于此)

您也可以完全不使用正则表达式来实现这一点,因为预处理器通常只遵循3条超级简单的规则(在伪代码中)

  • 如果第一个字母“#”=是指令
  • 而不是空格=指令的名称
  • 而不是换行符=表达式
  • 为了澄清函数创建问题。javascript的函数性质将函数分为函数声明和函数表达式。函数声明只计算一次,每次控件到达包含函数的行时,函数表达式都会进行计算,从而生成一个新函数,您还可以将其存储在变量o中r不是。如果不存储它,它将变成垃圾(例如,在您将其传递给returns的函数之后)


    您可以创建一个新的fileProcessor实例,然后在includeProcessor中使用它

    function includeProcessor(line) {
      if line matches "#include includefile"
      { 
        var fp = fileProcessorGen([includeProcessor, outputProcessor]);
        fp(includefile);  
      }
    };
    

    是的,它是有效的。但我的目的是实现关注点分离。Include Processor不应该知道使用了哪些其他处理器。我的目的是实现关注点分离。在这个示例中,只有两个行处理器,但实际上会有更多。而且调用方会选择一些行处理器用于其目的。顺便说一句,我想知道n我的解决方案是每次调用时都会创建行处理器函数吗?我认为函数是通过声明创建的,引用是在数组中传递的。我是JavaScript新手,如果我错了,请纠正我。@aleung我希望我能澄清一点。你并不是唯一一个有这种困惑的人。人们通常一开始都在寻找f或者是最新奇的功能,过一段时间后再使用最简单的功能,因为它们很容易写/读/维护/不会弄乱,而且通常性能更好:)
    function fileProcessor ( file ) {
        //split those lines
        lines.forEach( lineProcessor );
    }
    
    function lineProcessor ( line ) {
        if line matches "#include includefile"
            fileProcessor( includefile );
        else
            outputProcessor( line );
    }
    
    function outputProcessor ( line ) {
       //...
    }
    
    var directives = {
         include : function includeDirective ( expression ) {
         },
         define : function defineDirective ( expression ) {
         },
         //...
    };
    
    lines.forEach( function (line) { // creates one new function
      lineProcessors.forEach( function (processor) { //creates one new function per line
        processor.call(this, line);
      });// one function per line is now garbage
    }); // the outer function is now garbage
    
    function includeProcessor(line) {
      if line matches "#include includefile"
      { 
        var fp = fileProcessorGen([includeProcessor, outputProcessor]);
        fp(includefile);  
      }
    };