Javascript臭名昭著的循环问题?
我有以下代码片段Javascript臭名昭著的循环问题?,javascript,closures,Javascript,Closures,我有以下代码片段 function addLinks () { for (var i=0, link; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function () { alert(i); }; document.body.appen
function addLinks () {
for (var i=0, link; i<5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function () {
alert(i);
};
document.body.appendChild(link);
}
}
函数addLinks(){
对于第一个示例中的(var i=0,link;i),只需将此函数绑定到onclick事件:
function() {alert(i);};
这意味着在单击事件上,js应该提醒addlink函数i变量的值。由于for循环()的原因,它的值将为5
在第二个示例中,生成一个要与另一个函数绑定的函数:
function (num) {
return function () { alert(num); };
}
这意味着:如果使用值调用,则返回一个将提醒输入值的函数。例如,调用function(3)
将返回function(){alert(3)};
在每次迭代中使用值i调用此函数,因此为每个链接创建单独的onclick函数
要点是,在第一个示例中,您的函数包含一个变量引用,而在第二个示例中,在外部函数的帮助下,您将引用替换为实际值。这被称为闭包,大致上是因为您将函数中变量的当前值,而不是保留对它的引用。有关第一个示例的说明:
JavaScript的作用域是函数级的,而不是块级的,创建闭包只意味着将封闭作用域添加到封闭函数的词法环境中
循环终止后,函数级变量i的值为5,这是内部函数“看到”的值
在第二个示例中,对于每个迭代步骤,外部函数文字将计算为一个新的函数对象,该函数对象具有自己的作用域和局部变量num
,其值设置为当前值i
。由于num
从未被修改,它将在闭包的生命周期内保持不变:下一个迭代步骤不会覆盖旧值,因为函数对象是独立的
请记住,这种方法效率很低,因为必须为每个链接创建两个新函数对象。这是不必要的,因为如果使用DOM节点存储信息,它们很容易共享:
function linkListener() {
alert(this.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 = linkListener;
document.body.appendChild(link);
}
}
函数linkListener(){
警惕(本条第一款);
}
函数addLinks(){
对于(变量i=0;i<5;++i){
var link=document.createElement('a');
appendChild(document.createTextNode('link'+i));
link.i=i;
link.onclick=linkListener;
document.body.appendChild(链接);
}
}
基本上,在第一个示例中,您将onclick
处理程序内的i
直接绑定到onclick
处理程序外的i
上。因此,当onclick
处理程序外的i
改变时,onclick
处理程序内的i
也会改变
在第二个示例中,不是将其绑定到onclick
处理程序中的num
,而是将其传递到一个函数中,然后该函数将其绑定到onclick
处理程序中的num
。当您将其传递到函数中时,i
的值被复制,而不是绑定到num
。因此当i代码>更改,num
保持不变。之所以会发生复制,是因为JavaScript中的函数是“闭包”,这意味着一旦有东西被传递到函数中,它就被“关闭”以进行外部修改。其他人已经解释了发生了什么,这里有一个替代解决方案
function addLinks () {
for (var i = 0, link; i < 5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
with ({ n: i }) {
link.onclick = function() {
alert(n);
};
}
document.body.appendChild(link);
}
}
函数addLinks(){
对于(变量i=0,链接;i<5;i++){
link=document.createElement(“a”);
link.innerHTML=“link”+i;
带({n:i}){
link.onclick=函数(){
警报(n);
};
}
document.body.appendChild(链接);
}
}
基本上是穷人让装订。我喜欢为厚脸皮的人写简单的解释,因为我厚脸皮,所以就这样
我们在页面上有5个div,每个div都有一个ID…div1,div2,div3,div4,div5
jQuery可以做到这一点
for (var i=1; i<=5; i++) {
$("#div" + i).click ( function() { alert ($(this).index()) } )
}
for(var i=1;imm,我以前从未见过使用with语句的解决方案,nice;)在使用“with”语句时要小心。它有一些性能问题。我已经阅读了一些关于这个主题的答案,试图让我的头脑明白为什么。你最后一句话的后半部分终于在我脑海中打开了灯,…谢谢你,谢谢你,谢谢你!我注意到你需要更多的rep so+1来实现直截了当的版本!尽管我想我个人会把clickHandler
函数声明放在循环之外,只是为了风格。这是一个我仍然无法理解的问题。好吧。当你说“值是在调用函数时设置的”你的意思是,只有当点击div时,div的每个值才被设置?它通过引用保存在函数范围内,我知道我总是迟到,但无论如何。它被称为闭包。内部函数可以访问外部函数中的值,即使外部函数已返回。因此外部函数是一个IIFE,因此它存储num值。W当您单击时,内部函数将执行并返回num。我正在寻找一些关于闭包的好解释,以供演示……您的方法是目前为止最好的,值得称赞的。遗憾的是,这不再有效,警报将不会显示,控制台中也不会显示任何内容。请记住,扩展DOM(参见link.I=I;
)被认为是。@check\u ca,但是,同样的事情也可以通过数据属性或类似jQuery的.data()来完成。这些通常可以解决该文章中的问题(例如,数据是为用户保留的,因此未来的标准将永远不会定义数据属性)。“如果您使用DOM节点存储信息,它们可以很容易地共享”-非常有教育意义,谢谢!!@check\ca您会推荐什么替代方案?至少这种解决方案有效,与基于闭包的解决方案不同。@PhilippLudwig我建议用link.setAttribute(“数据链接索引”,I)替换link.I=I
并将警报(this.i)
替换为for (var i=1; i<=5; i++) {
$("#div" + i).click ( function() { alert ($(this).index()) } )
}
for (var i=1; i<=5; i++) {
$("#div" + i).click (
// TODO: Write function to handle click event
)
}
for (var i=1; i<=5; i++) {
$("#div" + i).click (
function(num) {
// A functions variable values are set WHEN THE FUNCTION IS CALLED!
// PLEASE UNDERSTAND THIS AND YOU ARE HOME AND DRY (took me 2 years)!
// Now the click event is expecting a function as a handler so return it
return function() { alert (num) }
}(i) // We call the function here, passing in i
)
}
for (var i=1; i<=5; i++) {
function clickHandler(num) {
$("#div" + i).click (
function() { alert (num) }
)
}
clickHandler(i);
}