8

好的,这是一个问题脚本。

var links = [ 'one', 'two', 'three' ];

for( var i = 0; i < links.length; i++ ) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.onclick = function() { alert( i ) }
    document.body.appendChild( a );
}

此脚本使用数组生成三个 div:一、二和三。
我在每个 div 上设置了一个(为简单起见是 Dom0)单击处理程序,它会提醒其在数组中的位置索引。- 除了它没有!它总是提醒 3,数组的最后一个索引。
这是因为 'alert(i)' 中的 'i' 是对外部范围(在本例中为全局)的实时引用,并且在循环结束时其值为 3。它需要的是一种在循环中取消引用 i 的方法。

这是一种解决方案,我倾向于使用它。

var links = [ 'one', 'two', 'three' ];

for( var i = 0; i < links.length; i++ ) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.i = i; //set a property of the current element with the current value of i
    a.onclick = function() { alert( this.i ) }
    document.body.appendChild( a );
}

其他人有什么不同的吗?
有没有真正聪明的方法?
有谁知道图书馆是如何做到这一点的?

4

4 回答 4

20

您需要使用这个小闭包技巧 - 创建并执行一个返回事件处理函数的函数。

var links = [ 'one', 'two', 'three' ];

for( var i = 0; i < links.length; i++ ) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.onclick = (function(i) { return function() { alert( i ) } })(i);
    document.body.appendChild( a );
}
于 2009-01-14T13:46:11.883 回答
4

我会保留您自己的解决方案,但可以通过以下方式对其进行修改:

var links = [ 'one', 'two', 'three' ];

function handler() {
    alert( this.i );
}

for( var i = 0; i < links.length; i++ ) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.i = i; //set a property of the current element with the current value of i
    a.onclick = handler;
    document.body.appendChild( a );
}

这样,只会创建一个函数对象 - 否则,函数字面量将在每个迭代步骤中进行评估!

通过闭包的解决方案在性能方面比您的原始代码更差。

于 2009-01-14T13:57:46.807 回答
1

我推荐使用Christoph的一种方法因为它使用的资源更少。

下面是另一种将值存储在函数上的方法(这是可能的,因为函数是一个对象)和用户argument.callee以获取对函数内部函数的引用。在这种情况下,它没有多大意义,但我展示了该技术,因为它可以在其他方面有用:

var links = [ 'one', 'two', 'three' ];

for( var i = 0; i < links.length; i++ ) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.onclick = function() { alert( arguments.callee.i ) }
    a.onclick.i = i;
    document.body.appendChild( a );
}

当您的函数需要在调用之间存储持久信息时,该技术很有用。用这个替换上面的部分:

a.id="div"+i;
a.onclick = function() {
    var me = arguments.callee;
    me.count=(me.count|0) + 1;
    alert( me.i );
}

并且您可以稍后检索它被调用的次数:

for( var i = 0; i < links.length; i++ ){
    alert(document.getElementById("div"+i).onclick.count);
}

它还可以用于在调用之间缓存信息。

于 2009-01-14T14:15:53.557 回答
0

RoBorg 的方法绝对是要走的路,但我喜欢稍微不同的语法。两者都完成了创建保留“i”的闭包的相同操作,这种语法对我来说更清楚,并且需要对现有代码的修改更少:

var links = ['一','二','三'];

for( var i = 0; i < links.length; i++ ) (function(i) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.onclick = function() { alert( i ) }
    document.body.appendChild( a );
})(i);
于 2009-01-15T00:29:13.957 回答