我正在用JavaScript(Node.js)编写文件处理器。简化的伪代码如下。对于文件中的每一行,它打印到输出,如果该行是包含指示符,则递归处理包含的文件。
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
}
也许我必须将fileProcessor作为参数传递给includeProcessor,但是如何?
function includeProcessor(line, fileProcessor) {
if line matches "#include includefile"
fileProcessor(includefile);
};
var fileProcessorGen = function (lineProcessors) {
return function (file) {
// read lines from file
lines.forEach( function (line) {
lineProcessors.forEach( function (processor) {
processor.call(this, line, ???); // <-- how to pass the parameter?
});
});
};
};
答案 0 :(得分:1)
您只需要为匿名函数指定一个名称,然后您可以在函数范围内通过该标识符引用它,无论您为该函数指定什么标识符。 (我几乎总是建议给出函数名,甚至函数表达式。不仅仅是为了能够引用它们而是为了更容易读取堆栈跟踪)。
function fileProcessorFactory (lineProcessors) {
return function fileProcessor (file) {
// read lines from file
lines.forEach( function (line) {
lineProcessors.forEach( function (processor) {
processor.call(this, line, fileProcessor );
});
});
};
};
var fileProcessorInstance = fileProcessorFactory( [ includeProcessor, outputProcessor ] );
但是你当然应该意识到你当前的解决方案是非常低效的,因为它每次被调用时都会创建全新的函数集,如果你只是声明它,你可以使它更简单,更有效。功能一次,让他们互相打电话。
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 ) {
//...
}
如果你想支持多个指令,只需在一个名为&#34;一个javascript对象&#34;的散列图中查找它们的名字。如果名称不在地图中,则抛出错误。 (还有ES6中的实际Map
数据类型,您也可以使用它)。
var directives = {
include : function includeDirective ( expression ) {
},
define : function defineDirective ( expression ) {
},
//...
};
你也可以在没有正则表达式的情况下完全执行此操作,因为预处理器通常只遵循3个超简单规则(伪代码)
澄清功能创建问题。 javascript的功能性将函数分离为函数声明和函数表达式。函数声明被计算一次,每次控件到达包含它的行时,都会计算函数表达式,从而产生一个新函数,您也可以将它存储在变量中。如果你不存储它就会变成垃圾(例如在你传递给它的函数返回之后)。
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
答案 1 :(得分:0)
您可以创建一个新的fileProcessor实例,然后在includeProcessor中使用它。
function includeProcessor(line) {
if line matches "#include includefile"
{
var fp = fileProcessorGen([includeProcessor, outputProcessor]);
fp(includefile);
}
};