2015-08-31 22 views
2

我想了解在实践中使用JavaScript中的功能样式的方法。我创建了一组简单的函数来处理字符串,但是我觉得我在做概念上的错误,因为它看起来就像命令式的风格,即使我不改变输入并且不改变应用程序中的应用程序状态功能。功能样式中应用于字符串的函数序列

下面是它的外观:

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种简单的处理功能。

如果我添加方法链,原型方法的思想也会反对功能风格,因为链中的函数将取决于之前的状态,而不仅仅取决于它们的输入。

我该怎么做才能让它在功能风格上看起来更漂亮?

更新:经过深入研究,我发现主题名为Function Composition。这似乎是解决问题的恰当办法,也是功能性世界的基本内容之一。 下面是我用撰写多种功能为一体的功能:

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) 

从右边跑到左边和所有工作得很好。

+0

你是什么意思“*如果我使用回调*运行序列”?为什么要这么做?你的字符串是否是异步的? – Bergi

+0

我不明白为什么原型方法会违反功能风格。作为方法,他们可能以非常规的语法获得第一个参数(对象),但它们也只是函数。它们以不变对象的方式工作。 – Bergi

+0

为什么'LineParser'是一个函数,你为什么需要调用它,它有什么作用? – Bergi

回答

-1

如果你想异步编程,但你不喜欢嵌套回调,你有没有考虑过async 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个系重)

+1

尽管异步编程是一种功能性风格,但功能性风格并不是异步编程。这就像声称车辆是汽车(完全无视卡车,自行车,船只和飞机等非车辆车辆)。 – slebetman

+0

@slebetman好的,但它是否让我的答案脱离主题?如果你认为我写了一些不正确的东西,请随意编辑文本 – bviale

0

您lineparser似乎变成有用的东西有如formatSpaces,capitalizeformatSomethingElse的方法。你可以做最简单的事情就是让所有这些方法来return this,这样就可以链接这些方法如下所示:

var outputline = LineParser.formatSpaces(inputLine).capitalize().formatSomethingElse() 

虽然由它的外观,所有的方法都需要一些字符串作为参数,所以你可能需要做一些实现的改变,比如将字符串保存在一个私有变量中,如果没有给出参数,则将其从变量中拉出。

+0

我试过了,但由于依赖于以前的应用程序状态,它似乎违反了功能风格。 –

+0

@SergeiBasharov也许你可以探索像http://functionaljs.com/这样的工作? JavaScript中的“功能”通常意味着利用'map','reduce'和'filter',而不是通过数组循环。 – Piwwoli

+0

@SergeiBasharov如果你想学习功能性JavaScript,那么你的这个lineparser可能不是最好的主意。如果我是你,我可能只会学习如何制作一些功能库。 – Piwwoli

-1

实用的风格,那就是,我们在Lisp语言等看纯功能性的风格是这样的:

var outputline = formatSomethingElse(capitalize(formatSpaces(inputline))); 

通常情况下,为便于阅读,它会被格式化为:

var outputline = formatSomethingElse(
    capitalize(
     formatSpaces(inputline) 
    ) 
); 
任何其他

形式不是功能风格。功能风格有点像Reverse Polish Notation,因为规定的操作应该反向读取。事实上,RPN本身就是一种函数式编程语法(正如Forth所体现的)。

有具有相似的外观和感觉功能的风格样式:方法链接:

var outputline = LineParser(inputline) 
    .formatSpaces() 
    .capitalize() 
    .formatSomethingElse() 
    .toString(); 

与实用的风格,方法链接阅读秩序。

尽管最着名的链接库jQuery改变了对象的状态,但并不是真的需要这样做。举例来说,LineParser的以下简单实现:

function LineParser (text) { 
    return { 
     text: text, 
     toString: function() {return this.text}, 
     capitalize: function() { 
      // return a new object instead of "this" 
      return { 
       text : _capitalize(this.text), 
       toString : this.toString 
      } 
     } 
    } 
} 
0

备注关于您的编辑。函数compose在原理中非常实用,但不在其实现中。事实上,该函数会使某些变量发生变异(例如,iargs),因此功能不完整。

为了避免使用这些变异变量,可以递归地定义compose。另一种解决方案应该依赖第三方功能库,例如下划线-js(http://underscorejs.org/),它已经定义了组合函数。

附加(显而易见)备注:为了使您的代码具有合成功能,编写的函数func1,func2,...不应改变它们的参数。

相关问题