JavaScript-递归调用部分应用函数
我正在用JavaScript(Node.js)编写一个文件处理器。简化的伪代码如下。对于文件中的每一行,它都打印输出,如果该行是一个include指示符,它将递归地处理包含的文件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
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);
}
};