我对闭包的理解是它们本质上是一个函数,它使用一个你认为超出范围的变量。我想这是我前几天看到的一个例子:
function closureMaker(somearg)
{
var local_value = 7;
function funcToReturn(arg1, arg2)
{
return local_value + somearg + arg1 + arg2;
}
return funcToReturn;
}
var myClosure = closureMaker(6); //make the closure
myClosure(2, 3); //using it
现在闭包有local_value甚至是原始的arg,somearg。但我不明白为什么这些都有帮助。使用'free'变量local_value有什么意义,甚至更不为我所知,为什么你会在闭包函数中使用closureMaking函数的参数?
我对如何在javascript中使用它更感兴趣,这是否对AJAX请求和对象使用了很多?
我得到了什么。我需要原因。
答案 0 :(得分:6)
闭包最实用和最广泛使用的一种方法是实现private or privileged members,例如:
function Test (param) {
var secret = 3;
function privateMethod() {
//...
}
this.publicMember = param;
this.privilegedMember = function () {
return secret * param;
};
}
var foo = new Test(10);
foo.privilegedMember(); // 30
foo.secret; // undefined
module pattern也是一个很好的例子,它可以使用相同的原理,例如:
var myModule = (function () {
var obj = {}, privateVariable = 1;
function privateMethod() {
// ...
}
obj.publicProperty = 1;
obj.publicMethod = function () {
// private members available here...
};
return obj;
}());
答案 1 :(得分:4)
常见的磨合是在for循环中,您需要提醒计数器的编号。
function addLinks () {
for(var i = 0; i < 5; ++i) {
var link = document.createElement('a');
link.appendChild(document.createTextNode('Link ' + i));
link.i = i;
link.onclick = function() { alert( i ) };
document.body.appendChild(link);
}
}
addLinks();
当您点击这些链接时,它会提醒5
,因为循环已经完成且i
等于5
。我们没有在执行for循环时“保存”i
的状态。
我们可以关闭“保存”该状态:
function addLinks () {
for(var i = 0; i < 5; ++i) {
var link = document.createElement('a');
link.appendChild(document.createTextNode('Link ' + i));
link.i = i;
link.onclick = (function(i) { return function() { alert(i ) } })(i);
document.body.appendChild(link);
}
}
addLinks();
i
绑定到循环中每个增量内调用的自执行匿名函数。通过这种方式,状态得以保存,我们在警报时获得正确的#。
答案 2 :(得分:4)
您正在查看的示例是试图向您展示闭包的工作原理。我认为闭包是你可以传递的一小段代码。巧妙的是,闭包中的(自由)变量基于当前的词法范围进行绑定。这就是local_value
保留值7
的原因,因为这是创建闭包时local_value
的值。
Javascript通过closures * 实现anonymous functions,但请记住,从技术上讲,这是两个独立的概念。
在Javascript的上下文中,当你想要处理异步发生的事情时,闭包(作为匿名函数实现)非常有用;一个很好的例子就像你说的那样,AJAX请求你无法预测何时从服务器获得响应。在这种情况下,您有一个名为 callback 的匿名函数,您最初定义并在进行AJAX调用时传入。调用成功完成后,将调用您的回调来处理结果。闭包会产生更清晰的代码,因为您可以将行为和逻辑打包在其中。它还可以帮助您抽象我们的行为和单独的问题。
匿名函数/闭包的另一个用途是用于事件处理。当事件发生时,您的事件处理程序将被调用。
就像我之前提到的那样,你可以抽象出行为和逻辑并把它放在一个闭包中。但真正使得闭包如此强大的是 context 。您可以自定义闭包的行为,具体取决于它的创建环境。这使得您的函数非常通用,因为您在创建它时定义它的参数(这会影响它的行为),而不是在执行期间调用它(使用显式参数)。
这是一篇关于Javascript中的闭包的好文章。这很长,但内容丰富:
* 正如CMS所提到的,名为的函数将表现得像匿名函数,因为它们可以访问在同一个词法中定义的变量范围(或链上的任何东西)。这在内部函数中最为明显。但是如果你考虑一下,任何功能都会发生同样的情况;您可以访问已在全局范围中定义的变量(即全局变量)。
答案 3 :(得分:0)
这可能不是你想要的,但是关于Java的闭包(它们应该/可以如何实现)有一个很好的讨论,这也是关于你想要使用它们的一些例子
答案 4 :(得分:0)
闭包是一种简单的方法,可以使函数依赖于参数。或者换句话说,创建一个系列函数的特定实例(如果不清楚则读取),具体取决于某些运行时值。
Javascript允许您将函数作为一等成员传递;例如,您可以通过直接引用它来传递一个确定如何组合两个整数的函数。
然而,更进一步,闭包允许您创建函数的“自定义”版本,其确切行为取决于某些运行时变量(但是否则符合框架)。
例如,这是一个允许添加curried的函数:
function getAddNFunction(n)
{
function inner(operand)
{
return n + operand;
}
return inner;
}
现在,如果你调用getAddNFunction(7)
,你会得到一个为参数添加7的函数。如果你调用getAddNFunction(42.5)
,你会得到一个为参数添加42.5的函数。
希望这个简单的例子澄清了闭包的好处;它们允许您在创建时在函数中嵌入参数,而不是必须在执行时传入它们(毕竟,调用getAddNFunction(9)(2)
与调用{{1}完全相同除了可以在非常不同的时间提供两个参数这一事实外。)
因此,例如,您可能希望返回某种相对于某个根元素的复杂XML解析函数;一个闭包允许你将根元素定义嵌入到函数本身中,而不是依赖于调用者在想要执行函数时有权访问它。
答案 5 :(得分:0)
如果您来自OO世界,那么闭包允许您为对象创建基本上私有的成员变量和方法:
function Constructor(...) {
var privateVar = value;
function privateFunc() {
}
this.publicFunc = function() {
// public func has access to privateVar and privateFunc, but code outside Constructor does not
}
}
答案 6 :(得分:0)
除了上面的闭包有助于隐藏一些实现细节。
var Counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
})();
alert(Counter.value()); /* Alerts 0 */
Counter.increment();
Counter.increment();
alert(Counter.value()); /* Alerts 2 */
Counter.decrement();
alert(Counter.value()); /* Alerts 1 */
Read this article on module pattern in javascript which heavily uses closures.