在循环中迭代函数的形参

Iterating parameters for a function within a loop

本文关键字:形参 函数 迭代 循环      更新时间:2023-09-26

JS noblord在这里,给一些背景,我最近创建了我的第一个基于JQuery的图像滑块,我目前正试图在页面加载时动态生成一个控制按钮列表。

到目前为止,我已经成功地创建了按钮,但是当谈到编写onclick函数时,我在for循环中调用另一个函数(带参数)时遇到了问题。

我不擅长解释事情,但下面是代码;

function addControls(){
    var x = document.getElementById('slider').childElementCount; 
    for (var i = 0; i < x; i++) {
        var ul = document.getElementById('slider-control');
        var li = document.createElement("li");
        var btn = document.createElement("Button");
        btn.onclick = function() { 
            goto(i); 
        };
        btn.appendChild(document.createTextNode(i + 1));
        ul.appendChild(li);
        li.appendChild(btn);
    }
}
function goto(index){
    alert(index);
}

这是JSFiddle预览。

我期望的是每个按钮调用goto函数与各自在循环中的位置,但是每个生成的按钮与onclick函数使用循环(4)的最后一个索引。

我最初的想法是按钮在循环完成后呈现,而不是在循环的每次迭代中?如果有人对我正在做的事情有任何建议和替代方案,我将不胜感激。

谢谢,

多德

正如Mikelis Baltruks评论的那样,您将不得不使用.bind

可以使用

goto.bind(null, i+1)

只映射索引到它。如果希望也获得按钮,可以使用

goto.bind(btn, i+1)
样本JSFiddle

绑定

.bind用于改变函数的上下文。其语法是

functionName.bind(context, argumentList);

这将创建一个带有新绑定上下文的函数引用。

也可以使用.apply。不同之处在于,apply期望参数为数组,而bind期望参数为逗号分隔的列表。

注意:这个函数只会注册事件而不会调用它。

参考

  • .bind
  • 苹果
  • 调用(),apply() vs bind()

问题是对i的引用。

for (var i = 0; i < x; i++) {
    var btn = document.createElement("Button");
    btn.onclick = function() { 
        goto(i);
        // any variable reference will use the latest value
        // so when `onclick` is actually run, the loop will have continued on to completion, with i == 4
    };
}

您需要为每个onclick处理程序引用一个单独的变量。你可以通过创建一个闭包来实现:

function makeOnclick(i) {
  // `i` is now a completely separate "variable",
  // so it will not be updated while the loop continues running
  return function() { goto(i); };
}
for (var i = 0; i < x; i++) {
    var btn = document.createElement("Button");
    btn.onclick = makeOnclick(i);
}

这可以通过多种方式实现,正如其他人所展示的那样。但这应该可以解释为什么会发生。

你需要在循环中创建一个闭包,这应该可以工作:

var x = document.getElementById('slider').childElementCount;
 for (var i = 0; i < x; i++) {
  (function (i) {
   var ul = document.getElementById('slider-control');
   var li = document.createElement("li");
   var btn = document.createElement("Button");
   btn.onclick = function() {
    goto(i);
   };
   btn.appendChild(document.createTextNode(i + 1));
   ul.appendChild(li);
   li.appendChild(btn);
  })(i);
}

function goto(index) {
  alert(index);
}
https://jsfiddle.net/g8qeq29e/6/

或与ES6 let关键字;

function addControls(){
    var x = document.getElementById('slider').childElementCount;
    for (let i = 0; i < x; i++) {//change var to let here
        var ul = document.getElementById('slider-control');
        var li = document.createElement("li");
        var btn = document.createElement("Button");
        btn.onclick = function() { 
            goto(i); 
        };
        btn.appendChild(document.createTextNode(i + 1));
        ul.appendChild(li);
        li.appendChild(btn);
    }
}
function goto(index){
    alert(index);
}