JS30. Задание 18 Tally String Times
Несложное упражнение. Есть список видео, у каждого видео в data-time атрибуте указана его продолжительность в минутах и секундах в формате: mm:ss. Нужно подсчитать общую продолжительность видео и вывести его в консоль.
Это задание я, пожалуй, могу выполнить и без подсказок автора и, возможно, даже без Google.
Моё решение
var videos = document.querySelectorAll(".videos li");
var arr = [];
for(var i = 0; i < videos.length; i++) {
var videoTime = videos[i].dataset.time;
arr.push(videoTime);
}
var arrTime = [];
for(var j = 0; j < videos.length; j++) {
arr[j] = arr[j].split(":");
var time = arr[j][0] * 60 + +arr[j][1];
arrTime.push(time);
}
var t = arrTime.reduce((a, b) => a + b);
var seconds = t % 60;
var mins = (t - seconds) % 3600 / 60;
var hours = (t - seconds - mins * 60) / 3600;
console.log(hours, mins, seconds)
Решение автора
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);
У автора лучше )
Сравниваю подходы
1. Я получаю объект NodeList. автор использует метод Array.from(), позволяющий получить массив из массивоподобного или итерируемого объекта
Зачем ему понадобился массив? Ведь перебор свойств методом forEach доступен и в
NodeList тоже. Но доступен ли для NodeList метод map? Нет, не доступен. Так что, если мы хотим применить к полученному объекту метод map (а мы хотим), нужно преобразовать NodeList в массив.
2. Интересная запись - метод map с точкой вначале пишется с новой строки. Аккуратность записи это повышает - мы избавляемся от длинных строк, понятность, как мне кажется, - нет.
В любом случае возможность переосить на новую строку часть выражения отделённую точкой нужно взять на заметку.
3. timeNodes.map(node => node.dataset.time) - эта строка автора аналог моего фрагмента кода
var arr = [];
for(var i = 0; i < videos.length; i++) {
var videoTime = videos[i].dataset.time;
arr.push(videoTime);
}
Безусловно, вариант автора лаконичнее удобнее и правильнее.
Почему у меня метод map() не сработал теперь понятно - я пыталась применить его к объекту, не преобразовав его в массив.
4. Авторский вариант
.map(timeCode => {
const [mins, secs] = timeCode.split(':').map(parseFloat);
return (mins * 60) + secs;
})
Мой:
var arrTime = [];
for(var j = 0; j < videos.length; j++) {
arr[j] = arr[j].split(":");
var time = arr[j][0] * 60 + +arr[j][1];
arrTime.push(time);
}
Здесь даже не знаю.
Метод map мне безусловно нравится. Но функцию parseFloat прекрасно заменяет унарный плюс, приводящий строку к числу, а вместо создания массива для минут и секунд я бы использовала индексы
Мой вариант выглядит так. Он чуть проще варианта автора. И он работает
.map(timeCode => {
timeCode = timeCode.split(':');
return timeCode[0] * 60 + +timeCode[1];
})
5. Редукция массива. Хоть что-то, что я умею
Вариант автора
.reduce((total, vidSeconds) => total + vidSeconds);
Мой:
var t = arrTime.reduce((a, b) => a + b);
Разница только в именах переменных и в том, что я результат присваиваю новой переменной, а автор продолжает цепочку преобразований.
Для меня мой вариант как минимум не хуже авторского.
6. Преобразование секунд в часы минуты и секунды
Вариант автора
let secondsLeft = seconds;
const hours = Math.floor(secondsLeft / 3600);
secondsLeft = secondsLeft % 3600;
const mins = Math.floor(secondsLeft / 60);
secondsLeft = secondsLeft % 60;
Мой:
var seconds = t % 60;
var mins = (t - seconds) % 3600 / 60;
var hours = (t - seconds - mins * 60) / 3600;
У меня лучше.
Окончательный вариант кода:
var videos = document.querySelectorAll(".videos li");
var videoArr = Array.from(videos);
var time = videoArr
.map(video => video.dataset.time)
.map(timeCode => {
timeCode = timeCode.split(':');
return timeCode[0] * 60 + +timeCode[1];
})
.reduce((a, b) => a + b);
var seconds = time % 60;
var mins = (time - seconds) % 3600 / 60;
var hours = (time - seconds - mins * 60) / 3600;
console.log(hours, mins, seconds)