sus*_*ani 23 javascript java closures
我正在阅读面向对象的Javascript,并发现了闭包的概念.我不太明白为什么以及何时使用它.像Java这样的其他语言也有闭包吗?我基本上想了解如何了解闭包的概念可以帮助我改进编码.
mik*_*era 24
闭包是具有绑定变量的第一类函数.
大致意味着:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
Oll*_*rds 13
关闭是以各种语言的各种名称知道的,但基本要点如下:
要创建闭包,您需要一种语言,其中函数类型是一等公民,即它可以绑定到变量并像任何旧字符串,int或bool一样传递.
您还需要能够内联声明函数.在javascript中你可以做这样的事情:
foo("bar", "baz" function(x){alert("x")});
Run Code Online (Sandbox Code Playgroud)
将匿名函数作为参数传递给foo函数.我们可以用它来创建一个闭包.
闭包"关闭"变量因此可用于传递范围变量.考虑这个例子:
function foo(){
var spam = " and eggs";
return function(food){alert(food + spam)};
}
var sideOfEggs = foo();
Run Code Online (Sandbox Code Playgroud)
鸡蛋的一面现在包含一个功能,它将"和鸡蛋"添加到它通过的任何食物中.垃圾邮件变量是foo函数范围的一部分,并且在函数退出时会丢失,除非闭包"关闭"命名空间,只要闭包保留在内存中,它就会保留它.
所以我们很清楚有权访问父母的私有范围变量吗?那么如何使用它们来模拟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"
Run Code Online (Sandbox Code Playgroud)
所以这里发生的是我们正在创建并立即调用匿名函数.函数中有一个私有变量.它返回一个带有引用此变量的方法的对象.函数退出后,getConstant方法是访问变量的唯一方法.即使删除或替换此方法,也不会放弃它的秘密.我们使用闭包来实现封装和变量隐藏.有关详细说明,请参阅http://javascript.crockford.com/private.html
Java还没有闭包.它最接近的是匿名内部类.然而,为了实例化这些内联中的一个,你必须实例化一个完整的对象(通常来自现有的接口).封闭的美妙之处在于它们封装了简单,富有表现力的语句,这些语句在匿名内部类的噪音中有些丢失.
虽然Java没有一流的功能,但事实上它确实有词法闭包.
例如,以下Lisp函数(从Paul Graham的书"On Lisp"中窃取)返回一个添加数字的函数:
(defun make-adder (n)
(lambda (x) (+ x n))
Run Code Online (Sandbox Code Playgroud)
这可以用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;
}
};
}
Run Code Online (Sandbox Code Playgroud)
内部的add()函数是一个词法闭包,因为它使用了外部词法范围中的n变量.
为了做到这一点,变量必须被声明为final,这意味着变量不能改变.但是,即使它们是最终的,也可以更改参考变量中的值.例如,考虑以下Lisp函数(也来自On Lisp):
(defun make-adderb (n)
(lambda (x &optional change)
(if change
(setq n x)
(+ n n))))
Run Code Online (Sandbox Code Playgroud)
这可以通过将外部变量包装在引用类型变量(例如数组或对象)中来实现.
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;
}
}
};
}
Run Code Online (Sandbox Code Playgroud)
我会声称这是真正的词汇封闭,而不是模拟.但我不会声称它很漂亮.
归档时间: |
|
查看次数: |
13630 次 |
最近记录: |