넘나 피곤하네요 하루에 2개 포스팅이란..
이번 게시물인 Day 18 project도 17번째와 약간은 비슷한 느낌이에요.
눈에 보이는 작업은 아니였지만, 언제든지 유용할 것 같은 주제랍니다.
바로 시작해볼게요!
HTML
에dataset
에 있는 모든 시간을 더해서 시간 단위로 변환한다.
<ul class="videos">
<li data-time="5:43">
Video 1
</li>
<li data-time="2:33">
Video 2
</li>
<li data-time="3:45">
Video 3
</li>
...
위와 같이 dataset
으로 시간이 있고, 총 58개의 시간 값을 더해서 시간단위로 변환해주는 작업이였습니다.
const timeNodes = [...document.querySelectorAll("[data-time]")];
const seconds = timeNodes.map(node => node.dataset.time).map(
time => {
const [mins, secs] = time.split(":").map(parseFloat);
return (mins * 60) + secs;
}
).reduce((total, eachSeconds) => total + eachSeconds);
let convertingSeconds = seconds;
const hours = Math.floor(convertingSeconds / 3600);
convertingSeconds = convertingSeconds % 3600;
const mins = Math.floor(convertingSeconds / 60);
convertingSeconds = convertingSeconds % 60;
console.log(`${hours}:${mins}:${convertingSeconds}`);
let
으로 선언된 부분부터는 시간으로 표현하기 위한 작업이라, 그 위에 친구들을 중점으로 정리해보겠습니다.
dataset
속성 뽑기먼저, HTML
구조가
<ul class="videos">
<li data-time="5:43">
Video 1
</li>
<li data-time="2:33">
Video 2
...
이와 같기 때문에, data-time
속성을 뽑아야합니다. 이는 다음 두 가지 방법으로 가능해요.
const timeNodes = [...document.querySelectorAll("[data-time]")];
const timeNodes = Array.from(document.querySelectorAll("[data-time]"));
그냥 간단하게
const timeNodes = document.querySelectorAll("[data-time]");
이렇게는 되지 않더라구요. 이는 timeNodes
가 배열이 아니라 NodeList
객체로 설정이 됨을 확인했습니다.
MDN
에 따르면,
Document
메소드querySelectorAll()
는 지정된 셀렉터 그룹에 일치하는 다큐먼트의 엘리먼트 리스트를 나타내는 정적(살아 있지 않은)NodeList
를 반환합니다.
이미 정의에 NodeList
를 반환한다고 나와있군요! 따라서 배열로 만들어주는 작업이 당연히 필요했습니다.
이는 두가지 방법으로 가능해요. 여기보시면 배열로 만드는 많은 방법이 있는데, 여기서는 그 중에서도 spread
와 Array.from()
을 사용했습니다.
const timeNodes = [...document.querySelectorAll("[data-time]")];
const timeNodes = Array.from(document.querySelectorAll("[data-time]"));
이를 수행하면, timeNodes
에는 <li>
배열이 58개가 들어가 있겠죠!
dataset.time
속성 모두 더해서 초단위로 표현하기const seconds = timeNodes.map(node => node.dataset.time).map(
time => {
const [mins, secs] = time.split(":").map(parseFloat);
return (mins * 60) + secs;
}
).reduce((total, eachSeconds) => total + eachSeconds);
추출한 timeNodes
의 원소 하나하나를 돌며 dataset.time
값을 추출하여 새로운 배열로 만듭니다. 그 배열을 또 map
함수를 써요!
time => {
const [mins, secs] = time.split(":").map(parseFloat);
return (mins * 60) + secs;
}
추출한 time
으로 새로운 배열을 만들었으니, 배열의 꼴은
["4:21", "3:22", ...]
이런꼴이였을 겁니다. 이 원소 하나하나를 이번에는 time
으로 지정하여, 초단위로 바꿔줘요.
처음에는
const [mins, secs] = time.split(":").map(parseFloat);
이 부분이 map
함수에 함수를 던져주면 알아서 하나? 싶었는데, MDN
에 예시부터가 이렇게 나와있더라구요. 원소 하나하나 돌면서 인자로 넘겨준 callback
함수를 수행하는 것으로 보입니다.
그렇다면 "3:19"
같은 time
이 ":"
로 split
되고, 바로 그 찢어진 숫자 문자열을 parseFloat
로 숫자화하여 [mins, secs]
에 집어 넣습니다.
더 복잡해지는 것 같아요. 😥
그렇게 생긴 [mins, secs]
는 (mins * 60) + secs
를 리턴하게 하여 reduce
함수를 수행합니다.
const seconds = timeNodes.map(node => node.dataset.time).map(
time => {
const [mins, secs] = time.split(":").map(parseFloat);
return (mins * 60) + secs;
}
).reduce((total, eachSeconds) => total + eachSeconds);
초기값이자 누적되는 변수인 total
에 현재 요소인 eachSeconds
가 하나하나 돌며 total
에 누적하여 더합니다.
그렇게 되면.. seconds
변수는.. 전체 합을 초단위로 가지고 있게 되는겁니다..!
이제 seconds
에는 총 시간이 초단위로 저장되어 있습니다! 이 친구를 변환해야죠 :)
let convertingSeconds = seconds;
const hours = Math.floor(convertingSeconds / 3600);
convertingSeconds = convertingSeconds % 3600;
const mins = Math.floor(convertingSeconds / 60);
convertingSeconds = convertingSeconds % 60;
console.log(`${hours}:${mins}:${convertingSeconds}`);
계속 값이 바뀌므로 let
으로 선언해서 사용했습니다.
수학적인 지식을 가미하면 쉽게 이해가 가능해요.
convertingSeconds
를 3600
으로 나누고 나머지를 버림을 하면 시간
단위이고, mod
연산을 하여 convertingSeconds
로 집어 넣습니다.분
단위이며..mod
연산한 값은 초
단위가 되는 겁니다!말로 풀어쓰니.. 어려워 보이는데, 수학적으로 생각해보면 당연한 느낌..!
급하게 적느라 두서없이 적힌 것 같네요..! 그래도 map
함수와 reduce
함수가 이번 과제에서 관건인 것 같아서, 그 친구만 잘 눈여겨 본다면 좋을 것 같아요.
늦었네요..! 틀린내용이나 수정할 내용이 있다면 언제든지 피드백 부탁드립니다!
감사합니다!🤗