for循环的当前迭代返回undefined并且函数的返回是未定义的

时间:2018-02-03 22:54:56

标签: javascript for-loop

我目前很难专注于没有像jQuery和co这样的框架的vanilla JavaScript。不幸的是,我知道在最后几天心理上令我不安的两个错误。我已经在互联网上搜索了,但我认为这些错误实际上太过个人化,而不是找到一般的解决方案或在网上工作。

这是我的index.htlml:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Songs</title>
  </head>
  <body>
    <div id="body-inner">
      <div class="playlist"></div> <br>
      <div class="song">
        <div class="current"></div> <br>
        <span class="time"></span>
        <button class="play">Play</button>
        <button class="pause">Pause</button>
      </div>
    </div>

    <script src="main.js"></script>
  </body>
</html>

这是我的main.js:

const [playlistOut, currentOut, timeOut] = [
  document.querySelector(".playlist"),
  document.querySelector(".current"),
  document.querySelector(".time")
];

// Create the App Object
let app = {
  playlists: {
    playlistSongs: [
      "Backseat",
      "Unforgettable",
      "BlueSkies",
      "Thunder",
      "Overflow",
      "Up&Down",
      "DoMyThing",
      "Heroes",
      "Miracles",
      "CakeByTheOcean",
      "InTheEnd",
      "Feel"
    ]
  },
  songDurations: {
    Backseat: 195,
    Unforgettable: 252,
    BlueSkies: 323,
    Thunder: 182,
    Overflow: 249,
    UpDown: 154,
    DoMyThing: 534,
    Heroes: 420,
    Miracles: 236,
    CakeByTheOcean: 379,
    InTheEnd: 231,
    Feel: 432
  },
  start: () => {
    showPlaylist(app.playlists.playlistSongs);
    clickSong();
  }
};

window.onload = app.start;

let test = {
  minutes: false,
  seconds: false
};

// Configure Timer
function startTimer(duration, display) {
  var timer = duration,
    minutes,
    seconds;
  if (duration != isNaN) {
    var timer = duration,
      minutes,
      seconds;
    interval = setInterval(() => {
      minutes = parseInt(timer / 60, 10);
      seconds = parseInt(timer % 60, 10);

      minutes = minutes < 10 ? "0" + minutes : minutes;
      seconds = seconds < 10 ? "0" + seconds : seconds;
      display.textContent = minutes + ":" + seconds;
      test.minutes = minutes;
      test.seconds = seconds;
      console.log("Minutes Func: " + minutes);
      console.log("Seconds Func: " + seconds);

      if (--timer < 0) {
        timer = 0;
      }
    }, 1000);
  } else {
    var error = "The given duration is not a number.";
    console.log(error);
    alert(error);
  }
  console.log("Inside Func: " + minutes);
  return { success: true, min: minutes, secs: seconds };
}

console.log("test.minutes: " + test.minutes);
console.log("test.seconds: " + test.seconds);

// Init Timer
let timerfunc = startTimer(60, timeOut);
console.log(timerfunc.min);

// Manage Play and Pause Buttons
document.querySelector(".pause").addEventListener("click", () => {
  clearInterval(interval);
});
document.querySelector(".play").addEventListener("click", () => {
  let currentDuration = timerfunc.min * 60 + timerfunc.secs;
  console.log(currentDuration);
  startTimer(currentDuration, timeOut);
});

// Show Playlist
function showPlaylist(playlist) {
  if (playlist.length > 0) {
    var constructor = {
      content: new Array()
    };
    for (var i = 0; i < playlist.length; i++) {
      constructor.content.push(
        '<a href="#" id="' +
          playlist[i] +
          '" class="song">' +
          playlist[i] +
          "</a><br>"
      );
    }
    playlistOut.innerHTML = constructor.content.join("");
    return true;
  } else {
    var error = "There is no playlist existing with this name.";
    console.log(error);
    return false;
  }
}

// Get the Time of the Element Clicked and Start the Timer

/* FIXME FIXME FIXME
songElements[i] returns undefined in l. 109 ff.
FIXME FIXME FIXME */

function clickSong() {
  var songElements = document.querySelectorAll(".song");
  for (var i = 0; i < songElements.length; i++) {
    songElements[i].addEventListener("click", function(e) {
      e.preventDefault;
      console.log(songElements[i].id);
      var songDuration = app.songDurations.songElements[i].id;
      startTimer(songDuration, timeOut);
      currentOut.innerHTML = "Currently Playing: " + songElements[i].id;
    });
  }
}

正如您所看到的,该应用程序是一个歌曲播放列表,您应该能够从播放列表中动态选择一首歌曲,并能够手动启动和停止歌曲。不幸的是,第53行的函数startTimer()并没有返回所需的值,因此脚本可以在用户再次手动停止后获取当前时间(以秒为单位)启动计时器。我已经用一堆console.log来修改代码,以便更好地理解变量的范围,但我仍然无法解决问题。

可以在clickSong()函数内的第133行找到下一个更重要的错误。我在那里获得了.song类的所有元素并将它们返回到节点列表中。在下一个回合中,我通过所述节点列表运行for循环,以在单击的excact元素上应用单击eventHandler。但是已经出现了问题:我无法点击该项目,实际上for循环第136行的当前迭代始终返回undefined。我遗憾地根本不知道如何解决这个问题。

您是否有想法或者您是否遇到类似情况?如果有帮助,我很高兴。

提前谢谢你,J0nny

2 个答案:

答案 0 :(得分:1)

问题是,在任何点击事件触发回调之前,您的i变量将达到for循环的结束值。因此,无论发生哪个点击事件,回调都会使用超出范围的i值。

您可以使用let代替var轻松解决此问题,因为这会为每次迭代创建一个新的变量实例,并且那个实例将在异步回调中引用。

for (let i = 0; i < songElements.length; i++) {

此表达式中出现第二个问题:

 app.songDurations.songElements[i].id

您的app.songDurations对象没有songElements属性,因此无效。你打算这个吗?

 app.songDurations[songElements[i].id]

答案 1 :(得分:1)

我改变了很多,所以只需尝试查看代码并查看更改内容

HTML

SELECT mi.*, group_concat(mc.contents)
FROM move_items mi LEFT JOIN
     move_contents mc
     ON mi.boxnumber = mc.box
GROPU BY mi.boxnumber
ORDER BY mi.date DESC;

JAVASCRIPT

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Songs</title>
</head>
<body>
<div id="body-inner">
    <div class="playlist"></div> <br>
    <div class="controls">
        <div class="current"></div> <br>
        <span class="time"></span>
        <button class="play">Play</button>
        <button class="pause">Pause</button>
    </div>
</div>

<script src="main.js"></script>
</body>
</html>

请注意,在我将const [playlistOut, currentOut, timeOut] = [ document.querySelector(".playlist"), document.querySelector(".current"), document.querySelector(".time") ]; // Create the App Object let app = { playList: [ "Backseat", "Unforgettable", "BlueSkies", "Thunder", "Overflow", "Up&Down", "DoMyThing", "Heroes", "Miracles", "CakeByTheOcean", "InTheEnd", "Feel" ], songDurations: { Backseat: 195, Unforgettable: 252, BlueSkies: 323, Thunder: 182, Overflow: 249, UpDown: 154, DoMyThing: 534, Heroes: 420, Miracles: 236, CakeByTheOcean: 379, InTheEnd: 231, Feel: 432 }, start: () => { renderPlayList(app.playList); clickSong(); } }; window.onload = app.start; let [playListInterval, currentMinute, currentSecond] = [0, 0, 0]; // Configure Timer function startTimer(duration, display) { currentMinute = parseInt(duration / 60, 10); currentSecond = parseInt(duration % 60, 10); if (!isNaN(duration)) { let timer = duration; playListInterval = setInterval(() => { currentMinute = parseInt(timer / 60, 10); currentSecond = parseInt(timer % 60, 10); const minutes = currentMinute < 10 ? "0" + currentMinute : currentMinute; const seconds = currentSecond < 10 ? "0" + currentSecond : currentSecond; display.textContent = minutes + ":" + seconds; if (--timer < 0) { timer = 0; } }, 1000); } else { const error = "The given duration is not a number."; console.log(error); alert(error); } } // Manage Play and Pause Buttons document.querySelector(".pause").addEventListener("click", () => { if (playListInterval !== 0) { clearInterval(playListInterval); playListInterval = 0; } }); document.querySelector(".play").addEventListener("click", () => { let currentDuration = currentMinute * 60 + currentSecond; startTimer(currentDuration, timeOut); }); // Show Playlist function renderPlayList(playlist) { if (playlist.length > 0) { const content = []; for (let i = 0; i < playlist.length; i++) { content.push( '<a href="#" id="' + playlist[i] + '" class="song">' + playlist[i] + "</a><br>" ); } playlistOut.innerHTML = content.join(""); return true; } else { const error = "There is no playlist existing with this name."; console.log(error); return false; } } // Get the Time of the Element Clicked and Start the Timer function clickSong() { const songElements = document.querySelectorAll(".song"); for (let i = 0; i < songElements.length; i++) { const currentElement = songElements[i]; currentElement.addEventListener("click", function (event) { event.preventDefault(); const songDuration = app.songDurations[currentElement.id]; if (playListInterval !== 0) { clearInterval(playListInterval); playListInterval = 0; } startTimer(songDuration, timeOut); currentOut.innerHTML = "Currently Playing: " + currentElement.id; }); } } 更改为<div class="song">的html中,当我尝试播放/暂停时,它告诉我它不是持续时间,因为它具有相同的eventListener作为歌曲列表