JS Array.reduce:遇到“未捕获的TypeError:无法读取未定义的属性[...]”

时间:2019-07-30 16:23:27

标签: javascript arrays class

我正在尝试完成JavaScript30的练习。我想知道为什么我想出的解决方案不起作用。

这个想法很简单。您有一个网页,其中视频时长存储在列表中,如下所示:

  <ul class="videos">
    <li data-time="5:43">
      Video 1
    </li>
    <li data-time="2:33">
      Video 2
    </li>
  </ul>

列表中实际上有58个项目。练习是计算所有视频的总时长(换句话说,获得列表中包含的所有时长的总和)。

我有用于课程制定者解决方案的代码,它与我的解决方案采用的路径不同。当我创建“时间”类时,它将持续时间存储为秒。我了解此解决方案,但我想了解为什么我的解决方案无法正常工作。

课程随附的解决方案:

  const timeNodes = Array.from(document.querySelectorAll('[data-time]'));

  const seconds = timeNodes
    .map(node => node.dataset.time)
    .map(timeCode => {
      const [mins, secs] = timeCode.split(':').map(parseFloat);
      return (mins * 60) + secs;
    })
    .reduce((total, vidSeconds) => total + vidSeconds);

    let secondsLeft = seconds;
    const hours = Math.floor(secondsLeft / 3600);
    secondsLeft = secondsLeft % 3600;

    const mins = Math.floor(secondsLeft / 60);
    secondsLeft = secondsLeft % 60;

    console.log(hours, mins, secondsLeft);

我(尚未运行)的解决方案:

function Time(hours = 0, minutes = 0, seconds = 0) {
    this.hours = hours;
    this.minutes = minutes;
    this.seconds = seconds;
    this.addTime = function(hours = 0, minutes = 0, seconds = 0) {
      const ajout = new Time(hours, minutes, seconds);
      this.add(ajout);
    }
    this.add = function(ajout) {
      let surplus = 0;
      // seconds
      this.seconds += ajout.seconds;
      while (this.seconds >= 60) {
        this.seconds -= 60;
        surplus++;
      }
      // minutes
      this.minutes += ajout.minutes + surplus;
      surplus = 0;
      while (this.minutes >= 60) {
        this.minutes -= 60;
        surplus++;
      }
      // hours
      this.hours += ajout.hours + surplus;
    }
    this.toString = function() {
      return `${this.hours} h ${this.minutes} min ${this.seconds} s`;
    }
  }

  function stringToTime (str) {
    let h, m, s = 0;
    const arr = str.split(':');
    while (arr.length > 3) {
      arr.shift();
    }
    if (arr.length == 3) {
      h = parseInt(arr.shift());
    }
    if (arr.length == 2) {
      m = parseInt(arr.shift());
    }
    if (arr.length == 1) {
      s = parseInt(arr.shift());
    }

    return new Time(h, m, s);
  }
  //const reducerForTime = (accumulator, currentValue = new Time()) => accumulator.add(currentValue) || new ();
  const reducerForTime = (accumulator, currentValue = new Time()) =>
    {
      console.log(currentValue);
      //console.log(`accumulator = ${accumulator.toString()}; currentValue = ${currentValue.toString()}`);
      accumulator.add(currentValue);
      console.log(`accumulator after adding = ${accumulator.toString()}`);
    };

  const videos = document.querySelectorAll('ul.videos li');
  let videoTimes = [];
  for (let i = 0; i < videos.length; i++) {
    videoTimes.push(stringToTime(videos[i].dataset.time));
  }
  console.log(videoTimes.reduce(reducerForTime).toString());

错误如下: 未捕获的TypeError:无法读取未定义的属性“ add”

您会注意到,我在reducer函数中添加了两行“ console.log”行,以尝试找出问题出在哪里。

我现在得到以下控制台输出:

Time {hours: 0, minutes: 2, seconds: 33, addTime: ƒ, add: ƒ, …}
accumulator after adding = 0 h 8 min 16 s
Time {hours: 0, minutes: 3, seconds: 45, addTime: ƒ, add: ƒ, …}
Uncaught TypeError: Cannot read property 'add' of undefined
    at reducerForTime (index-START.html:239)
    at Array.reduce (<anonymous>)
    at index-START.html:248
reducerForTime @ index-START.html:239
(anonymous) @ index-START.html:248

它所指的行是 248 239 。第 248 行是调用reduce函数的那一行。第 239 行是带有accumulator.add(currentValue);的行。我不知道为什么它不起作用,因为根据我的理解,累加器应保持一次迭代到下一次迭代,因此应该是一个Time对象,因此应该具有“ add”属性。为什么错误消息告诉我它是未定义的?

1 个答案:

答案 0 :(得分:1)

  

应将累加器从一次迭代保留到下一次

累加器等于您在上一次迭代中返回的值。您当前未在reducerTime中返回任何内容。更改为:

const reducerForTime = (accumulator, currentValue = new Time()) => {
  accumulator.add(currentValue);
  return accumulator;
};