I'm making a digital clock with ES5 ( no arrow stuff and so ). The location and temperature I'll do later. How can I improve/refactor the current code that I have with functional programming?
CodePen: https://codepen.io/Aurelian/pen/opaxqx?editors=1010
This is the HTML:
<div class="clock">
<div class="clock-ram">
<div class="clock-display">
<div class="clock-location">United Kingdom, Manchester</div>
<div class="clock-main">
<div class="clock-time"></div>
<div class="clock-widgets">
<div class="clock-widget clock-date"></div>
<div class="clock-widget clock-day"></div>
<div class="clock-widget clock-temperature">NAN</div>
</div>
</div><!-- /clock-main -->
<ul class="clock-weekdays">
</ul>
</div><!-- /display -->
</div><!-- /ram -->
</div> <!-- /clock -->
This is the JS:
// Get te location
// Make the : blink
//var location = document.querySelector('.clock-location');
function abbrev(a,b) {
return a.substr(0,b);
}
function checkTime(i) {
if (i < 10) {
i = "0" + i
};
return i;
}
function displayTime() {
var clockTime = document.querySelector('.clock-time');
var clockDate = document.querySelector('.clock-date');
var clockDay = document.querySelector('.clock-day');
var clockWeekdays = document.querySelector('.clock-weekdays');
while(clockWeekdays.firstChild) clockWeekdays.removeChild(clockWeekdays.firstChild);
var date = new Date();
var weekday = new Array(7);
weekday[0] = "Sunday";
weekday[1] = "Monday";
weekday[2] = "Tuesday";
weekday[3] = "Wednesday";
weekday[4] = "Thursday";
weekday[5] = "Friday";
weekday[6] = "Saturday";
var monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
var singleDay = [];
for (var i = 0; i < weekday.length; i++) {
var day = weekday[i];
var li = document.createElement('li');
li.textContent = abbrev(day,3);
if (i === date.getDay()) {
li.classList.add('active');
}
clockWeekdays.appendChild(li);
}
// Mechanics
var todayDay = weekday[date.getDay()];
var h = date.getHours();
var m = checkTime(date.getMinutes());
var s = checkTime(date.getSeconds());
var year = date.getFullYear();
var month = date.getMonth();
// Display
clockDay.textContent = abbrev(todayDay,3);
clockTime.textContent = h + ":" + m + ":" + s;
clockDate.textContent = monthNames[month] + " / " + year;
}
window.setInterval(displayTime, 1000);
//displayTime();
// Get the time
//Loop Throw weekdays - show 3 letters
CodePen: https://codepen.io/Aurelian/pen/opaxqx?editors=1010
-
\$\begingroup\$ Minor point. Your clock shows a location in the UK but the time day and date on the display are local. You need to show the time relative to UTC \$\endgroup\$Blindman67– Blindman672018年01月17日 17:18:25 +00:00Commented Jan 17, 2018 at 17:18
-
\$\begingroup\$ Yeah, though I was wondering how can I improve the whole code apart from location and temperature for now. The location and temperature are static. I'm learning JS and don't want to be overwhelmed by the google API and stuff for now :) \$\endgroup\$Aurelian Spodarec– Aurelian Spodarec2018年01月17日 19:12:05 +00:00Commented Jan 17, 2018 at 19:12
1 Answer 1
You have almost everything in a single function, displayTime
.
I'd start by refactoring the date-to-string manipulations into separate functions and leaving only DOM manipulation code in displayTime
:
// qs :: String -> Element
// formatTime :: Date -> String
// formatYearMonth :: Date -> String
function displayTime() {
let date = new Date();
// handle weekdays here
qs('.clock-time').textContent = formatTime(date);
qs('.clock-date').textContent = formatYearMonth(date);
}
formatTime
would be more readable IMO if we named your checkTime
function zeroPad
and used mm
/ss
for double-digit strings:
function formatTime(date) {
let zeroPad = (i) => ((i < 10) ? "0" : "") + i; // I know you said no arrow functions, but I can't resist
let h = date.getHours();
let mm = zeroPad(date.getMinutes());
let ss = zeroPad(date.getSeconds());
return `${h}:${mm}:${ss}`;
}
The weekday indicators can be created once and only get updated as necessary. This makes it obvious what part is dynamic:
let weekdayLIs = Array.from(qs('.clock-weekdays').children);
// I'm no fond of using the index here, can be changed to inspect the <li>
function isCurrentWeekday(idx) { return idx === date.getDay(); }
weekdayLIs.forEach((li, idx) => {
li.classList.toggle('active', isCurrentWeekday(idx));
});
I'm not sure what's the point of displaying the current weekday in two places, but if you insist:
qs('.clock-day').textContent = weekdayLIs.find((li,idx) => isCurrentWeekday(idx)).textContent;
As for creating the <li>
s corresponding to the weekdays, you can simply list them in HTML; this has the benefit of having all the structure defined in one place:
<ul class="clock-weekdays">
<li>Sun</li><li>Mon</li><li>Tue</li><li>Wed</li><li>Thu</li><li>Fri</li><li>Sat</li>
</ul>
-
\$\begingroup\$ Welcome to Code Review! That's a really good first answer; I hope you stay around and contribute some more. \$\endgroup\$Toby Speight– Toby Speight2018年01月19日 13:34:35 +00:00Commented Jan 19, 2018 at 13:34