假设您想要一个函数,当您创建新的 DOM 元素时,您可以使用该函数返回一个唯一的“id”值。现在,在 Java 之类的东西中,您可以创建一个带有内部私有计数器的类,然后有一个方法将计数器附加到某个前缀字符串。好吧,在 Javascript 中:
var getId = (function() {
var counter = 0;
return function() {
return "prefix" + counter++;
};
})();
现在变量“getId”绑定到一个由另一个函数创建的函数,并以这样一种方式创建,即它有一个在调用之间使用的持久变量。同样,如果我想拥有一系列“getId”函数(例如,我可能添加的每种类型的 DOM 元素一个),我可以这样做:
var getIdFunc = function(prefix) {
var counter = 0;
return function() {
return prefix + counter++;
};
};
var getId = {
'div': getIdFunc('div'),
'span': getIdFunc('span'),
'dl': getIdFunc('dl'),
// ...
};
现在我可以调用getId.div() 为新的<div> 获取新的“id”值。该函数是通过调用一个函数创建的,该函数提供隐藏在闭包中的两个值:前缀字符串(作为参数传入)和计数器(在闭包范围内声明的var)。
一旦您习惯了它,该设施就会非常灵活和有用,以至于您在回到没有它的环境时会感到痛苦。
哦,如果您尝试一下,这里有一个提示可以帮助您远离 StackOverflow:这是一个一直弹出的问题:
for (var i = 0; i < 10; ++i) {
var id = "foo" + i;
var element = document.getElementById(id);
element.onclick = function() {
alert("hello from element " + i);
};
}
这里有什么问题?好吧,该函数引用的“i”变量是该循环运行的范围内的“i”。您会注意到,该变量通过循环递增(呃,对吗?)。好吧,作为事件处理程序创建和分配的每一个小函数都将在闭包范围内共享相同的单个变量“i”。哎呀!解决方案是这样做:
for (var i = 0; i < 10; ++i) {
var id = "foo" + i;
var element = document.getElementById(id);
element.onclick = (function(iCopy) {
return function() {
alert("hello from element " + iCopy);
};
})(i);
}
我们将外部“i”复制到它自己的闭包范围中,所以现在每个事件处理程序都有自己的!
总结一下:一旦你习惯了,利用闭包的技术就会出现所有的时间。这不是进入无错误编程新仙境的免费门票。不要误会我的意思。然而,它是一个非常有用且灵活的范例。