与 lambda 函数参数混淆
Confusion with lambda function parameter
我试图在 for 循环中将 setTimeout 与 lambda 函数一起使用,但它仅从 for 循环的最后一次迭代中捕获 lambda 函数内容的最后一个参数。在 C# 中,我们可以创建一个新变量,每次将其传递给新的 lambda 函数时作为参数传递,但这在 javascript 中似乎不起作用。有什么线索吗?
我说的具体函数是setElementsByIdTimed()
var gElems = new Array();
document.addEventListener("DOMContentLoaded", function (event) {
//setElementsById('icon_anim_start' , "icon_anim_end");
//setTimeout(function() {setElementsById('icon_anim_end' , "icon_anim");} , 500);
var delay = setElementsByIdTimed('icon_anim_start' , "icon_anim_end" , 250);
setTimeout(function() {setElementsById('icon_anim_end' , "icon_anim");} , delay);
});
function getElementsById (elementID){
var elementCollection = new Array();
var allElements = document.getElementsByTagName("*");
for(i = 0; i < allElements.length; i++){
if(allElements[i].id == elementID)
elementCollection.push(allElements[i]);
}
return elementCollection;
}
function setElementsById (elementID, newID) {
var elems = new Array();
elems = getElementsById(elementID);
for (var i = 0; i < elems.length; i++)
{
elems[i].id = newID;
}
}
function setElementsByIdTimed (elementID, newID , ms) {
var elems = new Array();
elems = getElementsById(elementID);
console.log("elems.length: " + elems.length);
gElems = elems;
for (var i = 0; i < elems.length; i++) {
var index = i
setTimeout(function() {
setElementId(index, newID);
}, ms * i);
}
return ms * (elems.length-1);
}
function setElementId (index , newID) {
console.log ("gElems.length: " + gElems.length + " index: " + index);
gElems[index].id = newID;
}
})
而不是
for(var i = 0; i < elems.length; i++)
{
var index = i
setTimeout(function() {
setElementId(index, newID);
}, ms * i);
}
使用 IIFE - https://developer.mozilla.org/en-US/docs/Glossary/IIFE
for(var i = 0; i < elems.length; i++)
{
(function(index) {
setTimeout(function() {
setElementId(index, newID);
}, ms * index);
}(i));
}
问题出在
for(var i = 0; i < elems.length; i++)
{
var index = i
setTimeout(function() {
setElementId(index, newID);}, ms * i);
}
索引总是同一个变量。尝试:
for(var i = 0; i < elems.length; i++)
{
(function(index){
setTimeout(function() {
setElementId(index, newID);}, ms * i);
})(i);
}
每次您必须在循环中访问一个闭包中的变量时,您必须使用一个函数来访问它。您还可以使用应用于数组的 forEach:
elems.forEach(function(index){
setTimeout(function() {
setElementId(index, newID);}, ms * i);
}
});
这是一个经典的 JavaScript 闭包问题。基本上,索引变量只有一个实例,并且它是在 lambda 函数的上下文之外声明的。所以每个 lambda 函数都使用相同的索引,并且它们在循环完成后执行,因此索引在每次调用时看起来都是越界的。
要让它工作 index
必须有闭包作用域:
function setElementsByIdTimed(elementID, newID , ms)
{
var elems = new Array();
elems = getElementsById(elementID);
console.log("elems.length: " + elems.length);
gElems = elems;
for(var i = 0; i < elems.length; i++)
{
var index = i
setTimeout( setClosure(index,newID), ms * i);
}
return ms * (elems.length-1);
}
function setClosure( index, newID ) {
// this lambda is called after the timeout elapses
return function() {
setElementId(index, newID);}
}
你也可以玩一个自我调用的把戏,但有点费脑子:
function setElementsByIdTimed(elementID, newID , ms)
{
var elems = new Array();
elems = getElementsById(elementID);
console.log("elems.length: " + elems.length);
gElems = elems;
for(var i = 0; i < elems.length; i++)
{
var index = i
setTimeout( (function(idx,nid) {
return function () {
setElementId(idx,nid);}
})(index, newID),
ms * i);
}
return ms * (elems.length-1);
}
这些实际上是相同的解决方案,但第一种语法可能更容易掌握。
我试图在 for 循环中将 setTimeout 与 lambda 函数一起使用,但它仅从 for 循环的最后一次迭代中捕获 lambda 函数内容的最后一个参数。在 C# 中,我们可以创建一个新变量,每次将其传递给新的 lambda 函数时作为参数传递,但这在 javascript 中似乎不起作用。有什么线索吗?
我说的具体函数是setElementsByIdTimed()
var gElems = new Array();
document.addEventListener("DOMContentLoaded", function (event) {
//setElementsById('icon_anim_start' , "icon_anim_end");
//setTimeout(function() {setElementsById('icon_anim_end' , "icon_anim");} , 500);
var delay = setElementsByIdTimed('icon_anim_start' , "icon_anim_end" , 250);
setTimeout(function() {setElementsById('icon_anim_end' , "icon_anim");} , delay);
});
function getElementsById (elementID){
var elementCollection = new Array();
var allElements = document.getElementsByTagName("*");
for(i = 0; i < allElements.length; i++){
if(allElements[i].id == elementID)
elementCollection.push(allElements[i]);
}
return elementCollection;
}
function setElementsById (elementID, newID) {
var elems = new Array();
elems = getElementsById(elementID);
for (var i = 0; i < elems.length; i++)
{
elems[i].id = newID;
}
}
function setElementsByIdTimed (elementID, newID , ms) {
var elems = new Array();
elems = getElementsById(elementID);
console.log("elems.length: " + elems.length);
gElems = elems;
for (var i = 0; i < elems.length; i++) {
var index = i
setTimeout(function() {
setElementId(index, newID);
}, ms * i);
}
return ms * (elems.length-1);
}
function setElementId (index , newID) {
console.log ("gElems.length: " + gElems.length + " index: " + index);
gElems[index].id = newID;
}
})
而不是
for(var i = 0; i < elems.length; i++)
{
var index = i
setTimeout(function() {
setElementId(index, newID);
}, ms * i);
}
使用 IIFE - https://developer.mozilla.org/en-US/docs/Glossary/IIFE
for(var i = 0; i < elems.length; i++)
{
(function(index) {
setTimeout(function() {
setElementId(index, newID);
}, ms * index);
}(i));
}
问题出在
for(var i = 0; i < elems.length; i++)
{
var index = i
setTimeout(function() {
setElementId(index, newID);}, ms * i);
}
索引总是同一个变量。尝试:
for(var i = 0; i < elems.length; i++)
{
(function(index){
setTimeout(function() {
setElementId(index, newID);}, ms * i);
})(i);
}
每次您必须在循环中访问一个闭包中的变量时,您必须使用一个函数来访问它。您还可以使用应用于数组的 forEach:
elems.forEach(function(index){
setTimeout(function() {
setElementId(index, newID);}, ms * i);
}
});
这是一个经典的 JavaScript 闭包问题。基本上,索引变量只有一个实例,并且它是在 lambda 函数的上下文之外声明的。所以每个 lambda 函数都使用相同的索引,并且它们在循环完成后执行,因此索引在每次调用时看起来都是越界的。
要让它工作 index
必须有闭包作用域:
function setElementsByIdTimed(elementID, newID , ms)
{
var elems = new Array();
elems = getElementsById(elementID);
console.log("elems.length: " + elems.length);
gElems = elems;
for(var i = 0; i < elems.length; i++)
{
var index = i
setTimeout( setClosure(index,newID), ms * i);
}
return ms * (elems.length-1);
}
function setClosure( index, newID ) {
// this lambda is called after the timeout elapses
return function() {
setElementId(index, newID);}
}
你也可以玩一个自我调用的把戏,但有点费脑子:
function setElementsByIdTimed(elementID, newID , ms)
{
var elems = new Array();
elems = getElementsById(elementID);
console.log("elems.length: " + elems.length);
gElems = elems;
for(var i = 0; i < elems.length; i++)
{
var index = i
setTimeout( (function(idx,nid) {
return function () {
setElementId(idx,nid);}
})(index, newID),
ms * i);
}
return ms * (elems.length-1);
}
这些实际上是相同的解决方案,但第一种语法可能更容易掌握。