除了隐藏在像 JavaScript 这样的多范式/函数式语言中的信息之外,闭包的真正价值主张是什么?

What is a closure's real value proposition besides information hiding in multi-paradigm / functional languages like JavaScript?

当我第一次尝试理解闭包时,我遇到了一堵难以理解的计算机科学的纸墙,我必须在接触闭包之前理解它。然后我了解到,在更多的猴子看到,猴子做的基础上,虽然 JavaScript 关键字不允许 Java 的成语,(请原谅我在这里模糊的记忆):

JAVA:

class ObjectWithPrivateMember()
    {
    private int counter;
    public void ObjectWithPrivateMember()
        {
        counter = 0;
        }
    public void increment()
        {
        counter += 1;
        }
    public void decrement()
        {
        counter -= 1;
        }
    public void get_count()
        {
        return counter;
        }
    }

JavaScript(几年前的 ECMAScript)没有真正的 "private" / "protected" 关键字,但是 Java 习语的免费翻译可能是某种东西喜欢:

JAVA脚本:

var object_with_private_member = function()
    {
    var counter = 0;
    return {
        increment: function()
            {
            counter += 1;
            },
        decrement: function()
            {
            counter -= 1;
            },
        get_count: function()
            {
            return counter;
            }
        };
    }();

除了我对 "Ewwwww, duct tape to try to dress up JavaScript as something it's not," 的直接反应之外,我还把它记为 "Ok, that is how to shoehorn the Java idiom with obscure details of JavaScript. This probably affords little direct insight into what is great about JavaScript."

现在我回来解决问题 "What are closures really good for?"the Wikipedia entry 提供了一些细节并建议信息隐藏可能是主要用例,不仅在具有大量功能倾向的多范式语言中,而且在第一个 class 功能语言中也是常见的嫌疑人。当然它更详细并且提供了更多细微差别,但它表明教科书 "JavaScript object with private fields" 用例并不像我想象的那么切题。

对于纯函数式语言或具有函数式倾向的多范式语言中的闭包,优秀的函数式程序员会看到的真实用例是什么?它们主要用于信息隐藏吗(the Wikipedia article 提供了比上面的漫画更多的细微差别和细节,但至少乍一看我的想法是闭包在 JavaScript 中可能比创建私人成员的后门方式。

除了在纯/多范式函数式语言中隐藏信息的机制之外,还有其他主要用例吗?

根据我的经验,隐私问题是一个次要的考虑因素,尤其是对于不可变的值。如果他们无法更改,您为什么要关心谁看到它?

要了解闭包的价值,您首先必须了解 first-class 函数的价值,然后很容易看出何时可以方便地将一些数据与该函数相关联。

考虑尝试在不使用闭包的情况下从维基百科页面编写以下示例,但仍使用 filter 高阶函数:

// Return a list of all books with at least 'threshold' copies sold.
function bestSellingBooks(threshold) {
  return bookList.filter(
      function (book) { return book.sales >= threshold; }
    );
}

您需要找到一些其他方式将 threshold 传递给谓词函数。在 OOP 中,您将创建某种对象,例如:

class ThresholdFilter implements Filterable {
  private threshold;
  ThresholdFilter(threshold) {
    this.threshold = threshold;
  }

  bool filter(book) {
    return book.sales >= this.threshold;
  }
}

function bestSellingBooks(threshold) {
  return bookList.filter(new ThresholdFilter(threshold));
}

或者,您可以更改 filter 函数以接受某种私有通用数据结构来存储和传递,这会使 filter 和谓词函数更加复杂和耦合。闭包现在开始看起来不错,对吗?

还有很多案例表明闭包极大地减少了耦合并简化了使用高阶函数的代码。这是函数式程序如此简洁的主要原因。