在编程风格课程中,我们要求以“连续传递风格”和“糖果工厂风格”两种方式实现一些代码。

我们正在阅读的书是克里斯蒂娜·维迪拉·洛佩斯(Cristina Videira Lopes)的“编程风格的练习”(第5章和第8章)。

我们被要求用另一种语言来实现本书的示例代码(本书使用的是Python,现在我正在使用Javascript)。

为了理解我的问题,我将向您展示书中显示的两个主要区别:

糖果工厂风格

#!/usr/bin/env python
read_file(path_to_file):
    """
    Takes a path to a file and returns the entire contents of the
    file as a string
    """
    with open(path_to_file) as f:
        data = f.read()
   return data


def filter_chars_and_normalize(str_data):
     ...

.
.
.

print_all(sort(frequencies(remove_stop_words(scan(
filter_chars_and_normalize(read_file(sys.argv[1]))))))[0:25])


连续传球风格

#!/usr/bin/env python

def read_file(path_to_file, func):
    with open(path_to_file) as f:
       data = f.read()
    func(data, normalize)


def filter_chars(str_data, func):
    pattern = re.compile(’[\W_]+’)
    func(pattern.sub(’ ’, str_data), scan)


.
.
.


read_file(sys.argv[1], filter_chars)


Java脚本

const fs = require('fs');


var myArgs = process.argv.slice(2);

function read_file(path_to_file,callback){
    fs.readFile(path_to_file, "utf-8",(err, data) => {
        if (err) throw err;
        callback(data);
      });
}

function string_to_lower(str_data,callback){
    var data = str_data.toLowerCase()
    callback(data)
}

.
.
.

function TermFrequency(){
    read_file(myArgs[0],function(result){
        string_to_lower(result, function(result2){
            remove_non_alphanumeric(result2,function(result3){
                remove_stop_words(result3,function(result4){
                    frequencies(result4,function(result5,result6){
                            sort(result5,result6,function(result7,result8){
                            write_out(result7,result8)
                        })
                    })
                })
            })
        })
    })
}


从我的理解以及本书的示例中,上面用Javascript编写的内容都是Continuation传递,因为函数是作为参数传递的。但是同时,为了调用主函数,您需要使用与Candy Factory相同的“管道风格”调用。

给定上面用JS编写的代码,如何实现糖果工厂风格?该代码(基于回调)是糖果工厂还是连续传递样式?如何在不使用回调并同时信任JS的情况下编写以上代码?

最佳答案

我认为您在混淆两件事。糖果风格通常被称为功能组合。那是一个功能的输出是下一个功能的输入的地方。

f(g(h(1)))


h(1)输出一个值,它是g的输入,它输出一个值,并且是f的输入。

这与Javascript中用于异步操作的回调样式不同。

f(1,g)


f取值,进行处理并在以后调用g的地方。

通常,在JavaScript中,您将需要处理异步操作,但在这种情况下,您仅需要回调(继续)。像stringToLower这样的函数仅需要返回数据。

function string_to_lower (str) {
  return str.toLowerCase();
}


如果您要调整代码以遵循这些规则,那么您可以做一些更熟悉的事情:

function TermFrequency(){
  read_file(myArgs[0],function(result){
   write_out( sort(frequencies(remove_stop_words(remove_non_alphanumeric(string_to_lower(result))))));
  }
}


知道这是组成,我们可以使用另一个函数来进一步简化它。

function compose (...fns) {
  return function (value) {
    fns.reduce(function (result, fn) {
      return fn(result);
    }, value);
  }
}


我们可以这样使用它:

const processFile = compose(
  string_to_lower,
  remove_non_alphanumeric,
  remove_stop_words,
  frequencies,
  sort,
  write_out,
);

function TermFrequency(){
  read_file(myArgs[0], processFile);
}


现在,这看起来很陌生,但让我们逐步了解一下。该函数compose接受称为fns的参数列表。 ...(其余运算符)仅接受各个参数并将它们放入数组中。您会注意到compose函数返回了另一个函数。因此compose(omg)将返回另一个等待value的函数。提供值后,该功能将停止运行。我们用函数列表调用compose,它返回一个等待值的函数。我们将该功能分配给const processFile。然后,我们执行异步操作并将processFile设置为回调。回调(我们的compose函数)接收它正在等待的值,然后同步进行所有处理。

希望这可以清除一些问题。我还建议您查看Promise,这样您就不必处理回调。

JavaScript很有趣,因为它本身就是一种异步语言。另一方面,Python不是。这意味着在python中您可以使用eboth样式,但是在Javascript中,有时必须同时使用两种样式。

此外,请记住,在JavaScript中,存在一些回调,我们使用它们构造了Promise,我们使用了它们构造了Async / Await。了解回调流程对于能够更有效地使用更高级别的工具至关重要。

关于javascript - JS回调:延续传递还是糖果工厂风格?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52480246/

10-10 05:45