Javascript 以函数样式应用于字符串的函数序列
我试图理解在实践中使用JavaScript函数风格的方法。我已经创建了一组简单的函数来处理字符串,但我觉得我在概念上做得不对,因为它看起来就像命令式风格,即使我不改变输入,也不改变函数中应用程序的状态 下面是它的外观:Javascript 以函数样式应用于字符串的函数序列,javascript,functional-programming,Javascript,Functional Programming,我试图理解在实践中使用JavaScript函数风格的方法。我已经创建了一组简单的函数来处理字符串,但我觉得我在概念上做得不对,因为它看起来就像命令式风格,即使我不改变输入,也不改变函数中应用程序的状态 下面是它的外观: var LineParser = require('../modules/LineParser'); var inputLine = 'A line with multiple spaces'; var outputLine = LineParser()
var LineParser = require('../modules/LineParser');
var inputLine = 'A line with multiple spaces';
var outputLine = LineParser().formatSpaces(inputLine);
// 'A line with multiple spaces'
outputLine = LineParser().capitalize(outputLine);
// 'A Line With Multiple Spaces'
outputLine = LineParser().formatSomethingElse(outputLine);
// Some more formatting, then do further processing with outputLine
如果我使用回调运行序列,当我有10个简单的处理函数时,它会很快变成一组丑陋的嵌套回调
如果我添加方法链接,原型方法的想法也会与函数样式相反,因为链中的函数将依赖于以前的状态,而不仅仅依赖于它们获得的输入
我应该怎么做才能让它看起来更美观,更实用
更新:经过更深入的研究,我发现这个主题名为。这似乎是问题的正确解决方案,也是功能世界的基本内容之一。
下面是我用来将多个函数组合成一个函数的函数:
var compose = function () {
var funcs = arguments;
return function () {
var args = arguments;
for (var i = funcs.length; i-- > 0;) {
args = [funcs[i].apply(this, args)];
}
return args[0];
};
};
然后我做一篇作文:
var composedFunction = compose(func1, func2, ..., funcn)
从右到左运行,一切正常。如果您想要异步编程,但不喜欢嵌套回调,您考虑过lib吗? 你可以有这样的东西:
var LineParser = require('../modules/LineParser');
var inputLine = 'A line with multiple spaces';
async.waterfall([
function(callback) {
var result = LineParser().formatSpaces(inputLine);
callback(null, result);
},
function(arg1, callback) {
var result = LineParser().capitalize(arg1);
callback(null, result);
},
function(arg1, callback) {
var result = LineParser().formatSomethingElse(arg1);
callback(null, result);
}
], function (err, result) {
// retrieve the final string
});
如果您将LineParser方法修改为异步方法,这将变得非常有用,否则它只会使您的3行代码变重如果您想要异步编程,但不喜欢嵌套回调,您考虑过lib吗? 你可以有这样的东西:
var LineParser = require('../modules/LineParser');
var inputLine = 'A line with multiple spaces';
async.waterfall([
function(callback) {
var result = LineParser().formatSpaces(inputLine);
callback(null, result);
},
function(arg1, callback) {
var result = LineParser().capitalize(arg1);
callback(null, result);
},
function(arg1, callback) {
var result = LineParser().formatSomethingElse(arg1);
callback(null, result);
}
], function (err, result) {
// retrieve the final string
});
如果您将LineParser方法修改为异步方法,则可以将其转化为有用的内容,否则它只会使您的3行变得更重您的LineParser似乎有formatSpaces、capitalize和formatSomethingElse等方法。您可以做的最简单的事情是使所有这些方法都返回此值,这样您就可以像这样链接这些方法:
var outputline = LineParser.formatSpaces(inputLine).capitalize().formatSomethingElse()
尽管从外观上看,所有方法都需要一些字符串作为参数,因此您可能需要进行一些实现更改,例如,如果给定,则将字符串保存在私有变量中,如果未给定参数,则从变量中拉入字符串。您的lineparser似乎有formatSpaces之类的方法,大写并格式化一些东西。您可以做的最简单的事情是使所有这些方法都返回此值,这样您就可以像这样链接这些方法:
var outputline = LineParser.formatSpaces(inputLine).capitalize().formatSomethingElse()
尽管从外观上看,所有方法都需要一些字符串作为参数,因此您可能需要进行一些实现更改,例如,如果给定,则将字符串保存在私有变量中,如果未给定参数,则从变量中拉入字符串。函数式,即,我们在Lisp等中看到的纯函数式样式如下所示:
var outputline = formatSomethingElse(capitalize(formatSpaces(inputline)));
通常,为了便于阅读,其格式为:
var outputline = formatSomethingElse(
capitalize(
formatSpaces(inputline)
)
);
任何其他形式都不是功能性风格。函数样式有点像反向波兰符号,因为所述操作应以反向读取。实际上,RPN本身就是一种函数式编程语法,如Forth所体现的那样
有一种样式的外观与功能样式相似:方法链接:
var outputline = LineParser(inputline)
.formatSpaces()
.capitalize()
.formatSomethingElse()
.toString();
与函数样式不同,方法链接是按顺序读取的
虽然最著名的链接库jQuery改变了对象的状态,但实际上没有必要这样做。以LineParser的以下简单实现为例:
函数式风格,即我们在Lisp等中看到的纯函数式风格,如下所示:
var outputline = formatSomethingElse(capitalize(formatSpaces(inputline)));
通常,为了便于阅读,其格式为:
var outputline = formatSomethingElse(
capitalize(
formatSpaces(inputline)
)
);
任何其他形式都不是功能性风格。函数样式有点像反向波兰符号,因为所述操作应以反向读取。实际上,RPN本身就是一种函数式编程语法,如Forth所体现的那样
有一种样式的外观与功能样式相似:方法链接:
var outputline = LineParser(inputline)
.formatSpaces()
.capitalize()
.formatSomethingElse()
.toString();
与函数样式不同,方法链接是按顺序读取的
虽然最著名的链接库jQuery改变了对象的状态,但实际上没有必要这样做。以LineParser的以下简单实现为例:
评论你的编辑。函数compose在原理上很实用,但在实现上却不实用。实际上,该函数变异了一些变量,例如i和args,因此不是完全函数 为了避免使用这些变异变量,您可以递归地定义compose。另一个解决方案是依赖第三方函数库,例如下划线js,它已经定义了组合函数
另外一个明显的注释:要使代码具有compose的功能,函数func1、func2、,。。。这是组成,不应该改变他们的论点 评论您的编辑。函数compose在原理上很实用,但在实现上却不实用。英德 d、 该函数变异了一些变量,例如i和args,因此不是完全功能的 为了避免使用这些变异变量,您可以递归地定义compose。另一个解决方案是依赖第三方函数库,例如下划线js,它已经定义了组合函数
另外一个明显的注释:要使代码具有compose的功能,函数func1、func2、,。。。这是组成,不应该改变他们的论点 我试过了,但它似乎不符合功能性风格,因为它依赖于以前的应用程序状态。@SergeiBasharov也许你可以探索类似的东西是如何工作的?JavaScript中的Functional通常意味着使用map、reduce和filter,而不是在数组中循环。@SergeiBasharov哦,如果你想学习Functional JavaScript,你的这个lineparser可能不是最好的主意。如果我是你,我可能只会学习一些函数库是如何制作的。我尝试过,但由于依赖以前的应用程序状态,它似乎与函数式风格背道而驰。@SergeiBasharov也许你可以探索类似的东西是如何工作的?JavaScript中的Functional通常意味着使用map、reduce和filter,而不是在数组中循环。@SergeiBasharov哦,如果你想学习Functional JavaScript,你的这个lineparser可能不是最好的主意。如果我是你,我可能会学习一些函数库是如何制作的。虽然异步编程是一种函数式编程,但函数式编程不是异步编程。“这就像声称汽车就是汽车,完全忽略了非汽车的汽车,如卡车、自行车、船只和飞机。”斯莱贝特曼:好的,但这是否让我的回答偏离了主题?如果您认为我写的东西不正确,请随意编辑文本。异步编程是函数式的,函数式不是异步编程。“这就像声称汽车就是汽车,完全忽略了非汽车的汽车,如卡车、自行车、船只和飞机。”斯莱贝特曼:好的,但这是否让我的回答偏离了主题?如果您认为我写了一些不正确的东西,请随意编辑文本。如果我使用回调运行序列,您的意思是什么?你为什么要那样做?你的字符串函数是异步的吗?我不明白为什么原型方法会与函数风格相反。作为方法,它们可能以非常规语法获取对象的第一个参数,但它们也只是函数。它们特别适用于不可变对象。为什么LineParser是一个函数,为什么需要调用它,它做什么?回调是指将函数作为参数传递给其他函数,在函数编程环境中可能使用了错误的术语,就像FormatSomethingElsFormatSpaceSinPutline;。LineParser只是一个返回其他函数的函数,可以转换为包含函数的对象。是的,这是错误的术语,可能是错误的理解。外部函数调用的参数本身是通过对函数调用求值创建的,但您仍然在传递字符串,而不是函数,因此这里没有回调。实际上,我认为这种方法在函数式编程中是相当标准的,不会变得难看:-如果我使用回调来运行序列,这是什么意思?你为什么要那样做?你的字符串函数是异步的吗?我不明白为什么原型方法会与函数风格相反。作为方法,它们可能以非常规语法获取对象的第一个参数,但它们也只是函数。它们特别适用于不可变对象。为什么LineParser是一个函数,为什么需要调用它,它做什么?回调是指将函数作为参数传递给其他函数,在函数编程环境中可能使用了错误的术语,就像FormatSomethingElsFormatSpaceSinPutline;。LineParser只是一个返回其他函数的函数,可以转换为包含函数的对象。是的,这是错误的术语,可能是错误的理解。外部函数调用的参数本身是通过对函数调用求值创建的,但您仍然在传递字符串,而不是函数,因此这里没有回调。实际上,我认为这种方法在函数式编程中是相当标准的,不会变得难看:-