对于循环不按预期工作,我做错了什么?

时间:2014-11-14 17:01:03

标签: javascript loops

我正在制作一个表单,用户可以自己和另外5个人自行回复。每个客人都有一个文本字段用于他们的名字,然后是单选按钮(是或否),无论他们是否参加。默认情况下,Guest 1&显示2,然后有一个按钮,用户可以单击以添加另一个客人,直到客人#6。

来宾3 - 6包含在他们自己的对象中:

var guestThree = {
  name : document.querySelector('label[for="nameOfThirdGuest"]'),
  attendingYes : document.querySelector('label[for="guestThreeAttendingYes"]'),
  attendingNo : document.querySelector('label[for="guestThreeAttendingNo"]')
};
var guestFour = {
  name : document.querySelector('label[for="nameOfFourthGuest"]'),
  attendingYes : document.querySelector('label[for="guestFourAttendingYes"]'),
  attendingNo : document.querySelector('label[for="guestFourAttendingNo"]')
};
var guestFive = {
  name : document.querySelector('label[for="nameOfFifthGuest"]'),
  attendingYes : document.querySelector('label[for="guestFiveAttendingYes"]'),
  attendingNo : document.querySelector('label[for="guestFiveAttendingNo"]')
};
var guestSix = {
  name : document.querySelector('label[for="nameOfSixthGuest"]'),
  attendingYes : document.querySelector('label[for="guestSixAttendingYes"]'),
  attendingNo : document.querySelector('label[for="guestSixAttendingNo"]')
};

我使用以下函数隐藏客人的3 - 6,然后将其转换为上述对象的方法:

function hideFields() {
  this.name.style.display = "none";
  this.attendingYes.style.display = "none";
  this.attendingNo.style.display = "none";
}

我也与showFields中的上述函数相反:

function showFields() {
  this.name.style.display = "block";
  this.attendingYes.style.display = "block";
  this.attendingNo.style.display = "block";
}

所以这里的想法是,当点击添加访客按钮(分配给变量addGuest)时,将添加访客#3。然后,当它再次被点击时,将添加#4号客座,依此类推,直到#6。我已将guestThree - guestSix对象添加到以下数组中:

var extraGuests = [guestThree, guestFour, guestFive, guestSix];

然后使用以下for循环:

for (var guest = 0; guest < extraGuests.length; guest++) {
  addGuest.onclick = function() {
      extraGuests[guest].showFields();
  };
}

但这不起作用。我通过测试发现,guest方式一直循环到4而不执行showFields方法。如果我要在onclick事件之后添加一个中断,那么guestThree将显示但是就是这样(显然因为这是中断的工作原理)但是这至少表明循环按照我希望的方式工作 - 在某种程度上。

所以我问你们的是 - 我做错了什么?如何使guest变量不直接循环到4?我需要每次迭代都是0,1,2,最后是3,据我所知,这正是应该发生的事情?

干杯!

3 个答案:

答案 0 :(得分:3)

有两个问题:

首先,您要在每个循环上覆盖onclick上的addGuest,因此只有最后一个分配才能生存。因此,如果我们解决第二个问题(下面),您仍然只会显示最后一组字段。可能,我们希望处理程序分配一次,并让它显示&#34; next&#34;一组字段。

第二个问题是,您分配给onclick的功能对guest变量有持久参考,而不是副本 of it。所以稍后,当函数被调用时,它会在guest循环结束后看到值for。解决这个问题的主要选择是构建函数,Function#bind中描述了var extraGuests = [guestThree, guestFour, guestFive, guestSix]; var nextGuest = 0; addGuest.onclick = function() { var guest = extraGuests[nextGuest]; if (guest) { ++nextGuest; guest.showFields(); } }; 。但由于我们不需要或不需要循环,因此无关紧要。

相反,我建议一个变量告诉你要揭示的下一组字段是什么,然后只是一个使用它的函数:

{{1}}

答案 1 :(得分:2)

您已经closed over a loop variable,这意味着在他们被调用时,您的点击处理程序都会查看guest的单个值,即extraGuests.length(它在循环完成时定义的值)。

您需要在循环执行时捕获循环变量which can be done easily using an Immediately-invoked function expression。 :

for (var guest = 0; guest < extraGuests.length; guest++) {
  (function(ind){
     addGuest.onclick = function() {
        extraGuests[ind].showFields();
     };
  })(guest);
}

使用较新的语言功能可能有更好/更简洁的方法。

答案 2 :(得分:0)

也许这就是。

var guest = 0;
addGuest.addEventListener('click', function() {
  if(guest < extraGuests.length)
    extraGuests[++guest].showFields();
}, false);