今天的题目「看起来」没有任何的悬念。
请问点击第三个链接时弹出的值?
<div id="demo">
<a href="#">A</a>
<a href="#">B</a>
<a href="#">C</a>
<a href="#">D</a>
</div>
<script type="text/javascript">
var addHandlers = function(nodes) {
for (var i = 0; i < nodes.length; ++i) {
nodes[i].onclick = function(ev) {
alert(i * 100);
}
}
}
addHandlers(document.getElementById('demo').getElementsByTagName('a'));
「很不幸」的是,上述的这段代码没有按照原意实现,点击它们所有的链接都是为 400。这是因为「点击以后执行 i * 100 ,而这个 i 是循环结束以后的值,按照上面的循环后值为 4」。
如果按照期望的写法,也就是点击链接以后 alert 不同的值,可以用闭包。比如下面有几个解决方案
var addHandlers = function(nodes) {
for (var i = 0; i < nodes.length; ++i) {
(function () {
var j = i * 100;
nodes[i].onclick = function(ev) {
alert(j);
}
}) ();
}
}
「 期前也讨论过 ,只不过那时还没有了解闭包,详细」。类似的题目,在 《精通 Javascript》 中 23 页( 中文版 )有提及。
var addHandlers = function(nodes) {
for (var i = 0; i < nodes.length; ++i) {
nodes[i].onclick = function(idx) {
return function(ev) {
alert(idx * 100);
}
}(i);
}
}
「另,如果是使用 YUI 的话,可能会更直观些」
var addHandlers = function(nodes) {
for (var i = 0; i < nodes.length; ++i) {
YAHOO.util.Event.on(nodes[i], 'click', function(ev, idx) {
alert(idx * 100);
}, i);
}
}
使用闭包的话,必须注意两点:其一,就是避免出现无谓的匿名函数;其二,就是注意内存溢出。下面有几条有关闭包的参考链接。
- http://www.cn-cuckoo.com/wordpress/wp-content/uploads/2007/08/JavaScriptClosures.html
- http://www.felixwoo.com/article.asp?id=294
- http://www.cn-cuckoo.com/2007/08/01/understand-javascript-closures-72.html
- http://www.jibbering.com/faq/faq_notes/closures.html
- http://www.cristiandarie.ro/asp-ajax/JavaScriptClosureInheritance.html
- http://realazy.org/lab/js/closure.html
- http://www.ibm.com/developerworks/cn/web/wa-memleak/index.html