无法将传统for循环转换为for-each循环

时间:2014-12-22 20:41:36

标签: javascript for-loop

出于某种莫名其妙的原因,我无法将此循环转换为更自然的for (var player in fizzPlayers) { ... }循环:

  for (var i = 0; i < fizzPlayers.length; i++) {
    var player = fizzPlayers[i];
    var val = parseInt(player.value);
    if (val != 0) {
      active.push(player);
      actfact.push(parseInt(player.value));
      actname.push(capitaliseFirstLetter(player.id));
    }
  }

我想写这个更自然的方式,比如:

  for (var player in fizzPlayers) {
    var val = parseInt(player.value);
    if (val != 0) {
      active.push(player);
      actfact.push(parseInt(player.value));
      actname.push(capitaliseFirstLetter(player.id));
    }
  }

但它无法正常工作,您可以在底部的可运行代码段中看到。

为了进行调试,我在循环之前插入了这段代码:

  // prints undefined... but why?
  for (var player in fizzPlayers) {
    console.log(player.value);
  }

为5名玩家打印undefined。为什么?在程序的前面有一个类似的循环,其中for (var player in fizzPlayers) { ... }循环正常工作。

为什么会这样?我错过了什么?

&#13;
&#13;
var fizzLoaded = false;
var fizzDiv, fizzFrom, fizzTo, fizzPlayers;

function fizzLoad() {
  if (fizzLoaded) {
    return;
  }
  fizzLoaded = true;
  var fizzForm = document.getElementById('fizzbuzz');
  fizzFrom = document.getElementById('rangeFrom');
  fizzTo = document.getElementById('rangeTo');
  fizzPlayers = [
    document.getElementById('frodo'),
    document.getElementById('sam'),
    document.getElementById('merry'),
    document.getElementById('pippin'),
    document.getElementById('bilbo')
  ];
  fizzDiv = document.getElementById('fizzOut');
}

function restrictRange() {
  var rFrom = parseInt(fizzFrom.value);
  var rTo = parseInt(fizzTo.value);
  fizzTo.min = rFrom;
  fizzFrom.max = rTo;
}

function validateValues() {
  var rFrom = parseInt(fizzFrom.value);
  var rTo = parseInt(fizzTo.value);
  if (rTo < rFrom) {
    alert("Illegal range from " + rFrom + " to " + rTo);
    return false;
  }
  for (var player in fizzPlayers) {
    var val = parseInt(player.value);
    if (val < 0 || val > 100) {
      alert("Illegal value " + val + " for player " + player.id);
      return false;
    }
  }
  return true;
}

function capitaliseFirstLetter(string) {
      return string.charAt(0).toUpperCase() + string.slice(1);
}

function fizzing() {
  fizzLoad();
  restrictRange();
  if (!validateValues()) {
    fizzDiv.innerHTML = "Illegal inputs";
    return;
  }

  var table = "";
  var rFrom = parseInt(fizzFrom.value);
  var rTo = parseInt(fizzTo.value);
  var active = [];
  var actfact = [];
  var actname = [];

  // prints undefined... but why?
  for (var player in fizzPlayers) {
    console.log(player.value);
  }

  for (var player in fizzPlayers) {
    var val = parseInt(player.value);
    if (val != 0) {
      active.push(player);
      actfact.push(parseInt(player.value));
      actname.push(capitaliseFirstLetter(player.id));
    }
  }

  table += "<table>\n";
  table += "  <tr><th>Value</th><th>Message</th></tr>\n";
  for (var i = rFrom; i <= rTo; i++) {

    var msg = "";
    for (var p = 0; p < active.length; p++) {
      if (i % actfact[p] == 0) {
        msg += actname[p];
      }
    }
    if (msg == "") {
      msg = "" + i;
    }
    table += "  <tr><td>" + i + "</td><td>" + msg + "</td></tr>\n";
  }
  table += "</table>\n";

  fizzDiv.innerHTML = table;
}
&#13;
h1 {
    clear: left;
}

hr {
    clear: left;
}

label {
    display: inline-block;
    float: left;
    clear: left;
    width: 150px;
    text-align: left;
}
input {
  display: inline-block;
  float: right;
  text-align: right;
  padding-left:10px;
  width: 50px;
}
&#13;
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>FizzBuzz</title>
    <link rel="stylesheet" href="fizzbuzz.css">
    <script src="fizzbuzz.js" type="text/javascript"></script>
  </head>
  <body>
    <h1>Config</h1>
    <form id="fizzbuzz">
      <fieldset id="fizzControl" oninput="fizzing();">
        <label>Range From<input id="rangeFrom" type="number" min="1" max="100" value="1" required></label>
        <label>Range To<input id="rangeTo"   type="number" min="1" max="1024" value="100" required></label>
        <div id="players" >
          <label>Frodo<input id="frodo" type="number" min="0" max="100" value="3" required></label>
          <label>Sam<input id="sam" type="number" min="0" max="100" value="5" required></label>
          <label>Merry<input id="merry" type="number" min="0" max="100" value="0" required></label>
          <label>Pippin<input id="pippin" type="number" min="0" max="100" value="0" required></label>
          <label>Bilbo<input id="bilbo" type="number" min="0" max="100" value="0" required></label>
        </div>
      </fieldset>
    </form>
    <hr>
    <h1>Output</h1>
    <div id="fizzOut" >Change a value to get output (a snippet thing)</div>
    <script>fizzing();</script>
  </body>
</html>
&#13;
&#13;
&#13;

6 个答案:

答案 0 :(得分:9)

编写迭代Array元素的循环的惯用方法是forEach。正如评论所指出的,for... in用于对象键,而不是数组元素。

fizzPlayers.forEach(function(player) {
  var val = parseInt(player.value);
  if (val != 0) {
    active.push(player);
    actfact.push(parseInt(player.value));
    actname.push(capitaliseFirstLetter(player.id));
  }
});

您可以在all modern browsers (IE9 +)Array.prototype.forEach

MDN docs

答案 1 :(得分:4)

检查实际分配给player的内容:

> fizzPlayers = ["jim", "bob", "joe"]
> for (var player in fizzPlayers) {
    console.log(player);
  }
0
1
2

迭代对象会为您提供。数组的键是索引。在这种情况下,你最好使用常规for循环而不是for-for循环,因为如果你已经为数组分配了任何其他属性(如fizzPlayers.barg = 40;),for-each循环将为你提供这些属性名称以及


但是,如果您使用的是jQuery,则可以使用$.each

> $.each(fizzPlayers, function (index, player) { 
    console.log(index + ": " + player); 
  });
0: jim
1: bob
2: joe

请注意,回调有两个参数:索引和值。

答案 2 :(得分:3)

在Javascript中,for-each循环将索引分配给控件变量,因此您需要使用fizzPlayers[player]而不是player。你可能不喜欢它(我经常不喜欢),但这就是它的工作原理。

答案 3 :(得分:2)

你需要

for (var p in fizzPlayers) {
    console.log(fizzPlayers[p].value);
}

这是一种常见的烦恼。 ECMAScript 6 proposal

for (var player of fizzPlayers) {
    console.log(player.value);
}

答案 4 :(得分:1)

for in中的JavaScript循环遍历对象的可枚举属性。因此,您无法将其转换为经典的for循环。更正式地说,来自MDN

  

for ... in循环只迭代可枚举的属性。对象   从像Array和Object这样的内置构造函数创建的   从Object.prototype和。继承的非可枚举属性   String.prototype,例如String的indexOf()方法或Object   toString()方法。循环将遍历所有可枚举的循环   对象本身的属性以及对象从其继承的属性   构造函数的原型(属性更接近于对象中的对象)   原型链覆盖原型的属性。

答案 5 :(得分:1)

for-each循环分配索引

// prints undefined... but why?
for (var playerIndex in fizzPlayers) {
   console.log(fizzPlayers[playerIndex].value);
}

您可以考虑使用lo-dash这样的便利库来实现实用功能。