当您这样做时(假设photo = photos[i]
您在问题中遗漏了一个):
img.onclick = function() { window.location = 'pics/user/' + photo.user_id };
函数内部的变量photo
与函数外部引用的变量相同photo
。它不是在定义函数时获取变量当前值的快照;它只是对同一变量的引用。周围的循环在每次迭代时都会更改该变量的值,但它不会每次都创建一个新变量;它正在重用同一个。因此,您生成的所有函数都引用了完全相同的变量——唯一的一个photo
。
当任何人真正单击图像并调用该函数时,循环早已终止,并且photo
已从主程序的范围中消失,但它仍然存在于内存中,因为所有这些函数仍然具有对它的引用。他们会发现它仍然指向列表中的最后一项,因为那是分配给它的最后一项。
因此,您需要为每个 onclick 函数提供其自己的变量,该变量在创建函数后不会更改。在 Javascript 中做到这一点的方法,因为它没有块范围,是调用一个函数并将值作为参数传递。在函数内部声明的函数参数和变量(与photo
上面的非工作示例相反,它在函数内部使用但在函数外部声明)在每次函数调用时重新创建。当photo
被声明为函数参数时,每个 onclick 都会获得自己的副本,其他任何东西都无法修改,因此当有人最终单击图像时,它仍然具有正确的值。
如果它使用静态函数生成器函数可能会更清楚;真的没有理由做内联声明和调用的事情。您可以在循环外声明一次:
function makeOnclick(somePhoto) {
return function() { hotlink(somePhoto); }
}
然后循环体可以这样做:
img.onclick = makeOnclick(photo)
您正在调用makeOnclick
并将其photo
作为参数传递。该makeOnclick
函数在很远的地方声明,photo
即使您想要它也无法直接使用;它根本看不到那个变量。相反,它所拥有的只是它的本地参数somePhoto
——每次调用时都会将其创建为一个全新的变量makeOnclick
。它在调用时使用 的值初始化photo
,但它只是一个副本,因此当photo
在下一次循环迭代中发生更改时,该特定实例somePhoto
将保持不变。当下一次迭代调用makeOnclick
时,它将创建一个somePhoto
初始化为 的新值的新实例photo
,依此类推。所以即使makeOnClick
返回的内部函数是继承somePhoto
var,该 var 是专门为 ; 的实例创建的makeOnClick
。每个返回的函数都有自己的 private somePhoto
。
您上面的工作代码以稍微不同的方式做同样的事情。它不是makeOnclick
在循环外声明一次函数并多次调用它,而是每次通过循环将其重新声明为匿名函数,然后立即调用。这段代码:
img.onclick = (function(x) { blah(x); })(photo);
与此相同:
function foo(x) { blah(x); }
img.onclick = foo(photo);
无需给函数命名。在一般的 JavaScript 中,这是:
(function (x,y,z) { doSomething(x,y,z); })(a,b,c);
与此相同:
function callDoSomething(x,y,z) { doSomething(x,y,z); }
callDoSomething(a,b,c);
除了函数没有名称并且没有保存在任何地方;它在被调用后立即消失。
因此,每次通过循环声明 onclick-generator 函数并立即立即调用它既简洁又好,但效率不高。