javascript 什么是闭包?java有闭包吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3805474/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 02:18:12  来源:igfitidea点击:

What is a closure? Does java have closures?

javajavascriptclosures

提问by sushil bharwani

I was reading Object Oriented Javascript and found the concept of closures. I didn't quite understand why and when it is used. Do other languages like Java also have closures? I basically want to understand how knowing the concept of closures can help me improve my coding.

我正在阅读面向对象的 Javascript 并发现了闭包的概念。我不太明白为什么以及何时使用它。Java 等其他语言也有闭包吗?我基本上想了解了解闭包的概念如何帮助我改进我的编码。

采纳答案by mikera

A closure is a first class function with bound variables.

闭包是具有绑定变量的第一类函数。

Roughly that means that:

大致意思是:

  • You can pass the closure as a parameter to other functions
  • The closure stores the value of some variables from the lexical scope that existed at the time that is was created
  • 您可以将闭包作为参数传递给其他函数
  • 闭包存储了创建时存在的词法作用域中一些变量的值

Java initially didn't have syntactic support for closures (these were introduced in Java 8), although it was fairly common practice to simulate them using anonymous inner classes. Here's an example:

Java 最初没有对闭包的语法支持(这些是在 Java 8 中引入的),尽管使用匿名内部类模拟它们是相当普遍的做法。下面是一个例子:

import java.util.Arrays;
import java.util.Comparator;

public class StupidComparator { 
    public static void main(String[] args) {
        // this is a value used (bound) by the inner class
        // note that it needs to be "final"
        final int numberToCompareTo=10;

        // this is an inner class that acts like a closure and uses one bound value
        Comparator<Integer> comp=new Comparator<Integer>() {
            public int compare(Integer a, Integer b) {
                int result=0;
                if (a<numberToCompareTo) result=result-1;
                if (b<numberToCompareTo) result=result+1;
                return result;
            }
        };

        Integer[] array=new Integer[] {1,10, 5 , 15, 6 , 20, 21, 3, 7};

        // this is a function call that takes the inner class "closure" as a parameter
        Arrays.sort(array,comp);

        for (int i:array) System.out.println(i);
    }
}

回答by Ollie Edwards

Closures are know by various names in various languages but the essential points are as follows:

闭包在各种语言中有各种名称,但要点如下:

To create closures you need a language where the function type is a 1st class citizen i.e. it can be bound to a variable and passed around like any old string, int or bool.

要创建闭包,您需要一种语言,其中函数类型是一等公民,即它可以绑定到一个变量并像任何旧字符串、int 或 bool 一样传递。

You also need to be able to declare functions inline. In javascript you can do something like this:

您还需要能够声明内联函数。在 javascript 中,您可以执行以下操作:

foo("bar", "baz" function(x){alert("x")});

To pass a anonymous function as a parameter to the foo function. We can use this to create a closure.

将匿名函数作为参数传递给 foo 函数。我们可以使用它来创建一个闭包。

Closures "close over" variables so can be used to pass scoped variables around. Consider this example:

闭包“关闭”变量,因此可用于传递范围变量。考虑这个例子:

function foo(){
    var spam = " and eggs";
    return function(food){alert(food + spam)};
}
var sideOfEggs = foo();

The side of eggs now contains a function which appends " and eggs" to whatever foodstuff it is passed. The spam variable is part of the foo function scope and would have been lost when the function exited, except that the closure "closed over" the namespace preserving it as long as the closure remains in memory.

鸡蛋的一侧现在包含一个函数,该函数将“和鸡蛋”附加到它传递的任何食物上。spam 变量是 foo 函数作用域的一部分,并且在函数退出时会丢失,除非闭包“关闭”了名称空间,只要闭包保留在内存中就可以保留它。

So we're clear on closures having access to their parent's private scoped variables right? So how about using them to simulate private access modifiers in javascript?

所以我们很清楚闭包可以访问其父级的私有范围变量,对吗?那么如何使用它们来模拟 javascript 中的私有访问修饰符呢?

var module = (function() {   
    var constant = "I can not be changed";

     return {
         getConstant    :    function() {  //This is the closure
            return constant;               //We're exposing an otherwise hidden variable here
         }
    };
}());                                     //note the function is being defined then called straight away

module.getConstant();                     //returns "I can not be changed"
module.constant = "I change you!";
module.getConstant();                     //still returns "I can not be changed" 

So what's happening here is we're creating and immediately calling an anonymous function. There is one private variable in the function. It returns an object with a single method which references this variable. Once the function has exited the getConstant method is the sole way of accessing the variable. Even if this method is removed or replaced it will not give up it's secret. We have used closures to achieve encapsulation and variable hiding. For a more thorough explanation of this see http://javascript.crockford.com/private.html

所以这里发生的事情是我们正在创建并立即调用一个匿名函数。函数中有一个私有变量。它返回一个带有引用此变量的单个方法的对象。一旦函数退出,getConstant 方法就是访问变量的唯一方法。即使这种方法被删除或替换,它也不会放弃它的秘密。我们已经使用闭包来实现封装和变量隐藏。有关对此的更彻底解释,请参见http://javascript.crockford.com/private.html

Java does not have closures (yet). The closest it has are anonymous inner classes. However to instantiate one of these inline you have to instantiate an entire object (usually from an existing interface).The beauty of closures is they encapsulate simple, expressive statements which is somewhat lost in the noise of anonymous inner classes.

Java 还没有闭包(还没有)。最接近的是匿名内部类。然而,要实例化其中一个内联对象,您必须实例化整个对象(通常来自现有接口)。闭包的美妙之处在于它们封装了简单、富有表现力的语句,这在匿名内部类的噪音中有些失落。

回答by Soulman

While Java doesn't have first-class functions, it does in fact have lexical closures.

虽然 Java 没有一流的函数,但它实际上有词法闭包。

For instance, the following Lisp function (stolen from Paul Graham's book On Lisp) returns a function that adds a number:

例如,以下 Lisp 函数(从 Paul Graham 的 On Lisp 一书中窃取)返回一个添加数字的函数:

(defun make-adder (n)
  (lambda (x) (+ x n))

This can be done in Java. However, since it doesn't have first-class functions, we need to define an interface (let's call it Adder) and an anonymous inner class with a function that implements this interface.

这可以在 Java 中完成。但是,由于它没有一流的函数,所以我们需要定义一个接口(我们称之为Adder)和一个匿名内部类,并带有实现该接口的函数。

public interface Adder {
    int add(int x);
}

public static Adder makeAdder(final int n) {
    return new Adder() {
        public int add(int x) {
            return x + n;
        }
    };
}

The inner add()function is a lexical closure because it uses the nvariable from the outer lexical scope.

内部add()函数是一个词法闭包,因为它使用外部词法作用域中的n变量。

The variable had to be declared finalin order to do this, which means that the variable cannot change. However, changing values within reference variables is possible, even if they are final. For instance, consider the following Lisp function (also from On Lisp):

为了做到这一点,变量必须被声明为final,这意味着变量不能改变。然而,改变引用变量中的值是可能的,即使它们是最终的。例如,考虑以下 Lisp 函数(同样来自 On Lisp):

(defun make-adderb (n)
  (lambda (x &optional change)
    (if change
        (setq n x)
        (+ n n))))

This can be implemented in Java by wrapping the outer variable in a reference type variable, such as an array or object.

这可以在 Java 中通过将外部变量包装在引用类型变量(例如数组或对象)中来实现。

public interface MutableAdder {
    int add(int x, boolean change);
}

public static MutableAdder makeAdderB(int n) {
    final int[] intHolder = new int[] { n };
    return new MutableAdder() {
        public int add(int x, boolean change) {
            if (change) {
                intHolder[0] = x;
                return x;
            }
            else {
                return intHolder[0] + x;
            }
        }
    };
}

I will claim that this is real lexical closures, not a simulation. But I won't claim that it's pretty.

我会声称这是真正的词法闭包,而不是模拟。但我不会说它很漂亮。

回答by Ken Struys

Closure is a very natural feature that allows free-variables to be captured by their lexical environment.

闭包是一个非常自然的特性,它允许自由变量被它们的词法环境捕获。

here's an example in javascript:

这是 javascript 中的一个示例:

function x() {

    var y = "apple";

    return (function() {
         return y;
    });
}

function x returns a function. note that when a function is created variables used in this function are not evaluated like when we return an expression. when the function is created it looks to see what variables are not local to the function (free). It then locates these free variables and ensures they are not garbage collected so that they can be used once the function is actually called.

函数 x 返回一个函数。请注意,创建函数时,该函数中使用的变量不会像返回表达式时那样进行评估。创建函数时,它会查看哪些变量不是函数的局部变量(免费)。然后它定位这些自由变量并确保它们不会被垃圾收集,以便在实际调用函数后可以使用它们。

In order to support this feature you need to have first-class functions which java does not support.

为了支持这个特性,你需要有java不支持的一流功能。

Note this is a way we can have private variables in languages like JavaScript.

请注意,这是我们可以在 JavaScript 等语言中拥有私有变量的一种方式。

回答by hvgotcodes

A closure is a scoping technique. Java does not have closures.

闭包是一种作用域技术。Java 没有闭包。

In javascript you can do something like that following:

在 javascript 中,您可以执行以下操作:

var scope = this;

var f = function() {
    scope.somethingOnScope //scope is 'closed in' 
}

if you then do something like pass f to a function, scope is the scope of where it was defined.

如果您随后执行诸如将 f 传递给函数之类的操作,则作用域是定义它的位置的作用域。