Nội dung bài viết
Bài toán rất đơn giản: hiển thị ngày giờ hiện tại lên trang web và tự cập nhật mỗi giây. Đây là bài tập quen thuộc khi mới học JavaScript, nhưng nó có vài chỗ dễ sai đáng nói.
Phiên bản đầu tiên
function Clock() {
var today = new Date();
var date = today.getDate() + '-' + (today.getMonth() + 1) + '-' + today.getFullYear();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
document.getElementById("current-time").innerHTML = date + ' ' + time;
}
setInterval(Clock, 1000);
Và phần HTML để đặt đồng hồ vào chỗ bạn muốn:
<div id="current-time"></div>
Vài điểm cần giải thích:
new Date()không tham số trả về thời điểm hiện tại theo giờ máy người dùng.getMonth()trả về giá trị từ 0 đến 11, nên phải cộng thêm 1. Đây là lỗi kinh điển khiến tháng 9 hiển thị thành tháng 8.setInterval(Clock, 1000)gọi lại hàm mỗi 1000 mili giây.
Hai lỗi cần sửa
Lỗi thứ nhất: thiếu số 0 ở đầu. Đến 9 giờ 5 phút 3 giây, đoạn code trên in ra 9:5:3 thay vì 09:05:03. Nhìn rất khó chịu và độ rộng khối chữ nhảy liên tục.
Lỗi thứ hai: đồng hồ đứng yên trong giây đầu tiên. setInterval chờ hết 1000ms rồi mới chạy lần đầu, nên trang vừa tải xong sẽ trống một giây.
Ngoài ra còn một cái bẫy nữa: nếu HTML của bạn dùng class="current-time" mà JavaScript lại gọi getElementById thì sẽ không tìm thấy phần tử nào và trình duyệt báo lỗi Cannot set property 'innerHTML' of null. Selector phải khớp với thứ bạn khai báo trong HTML.
Phiên bản hoàn chỉnh
function pad(n) {
return String(n).padStart(2, "0");
}
function updateClock() {
const el = document.getElementById("current-time");
if (!el) return;
const now = new Date();
const date = `${pad(now.getDate())}-${pad(now.getMonth() + 1)}-${now.getFullYear()}`;
const time = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
el.textContent = `${date} ${time}`;
}
updateClock(); // chạy ngay, không chờ 1 giây
setInterval(updateClock, 1000);
Những thay đổi đáng chú ý:
padStart(2, "0")thêm số 0 vào đầu cho đủ hai chữ số.- Gọi
updateClock()một lần trước khi vàosetIntervalđể đồng hồ hiện ngay lập tức. - Dùng
textContentthay choinnerHTML. Nội dung ở đây là văn bản thuần, không cần trình duyệt phân tích HTML, nêntextContentvừa nhanh hơn vừa loại bỏ hoàn toàn nguy cơ XSS nếu sau này bạn ghép thêm dữ liệu từ bên ngoài vào. - Kiểm tra
if (!el) return;để script không văng lỗi khi phần tử chưa tồn tại.
Dùng Intl cho định dạng tiếng Việt
Nếu bạn muốn định dạng theo chuẩn địa phương thay vì tự ghép chuỗi, trình duyệt đã có sẵn công cụ:
const formatter = new Intl.DateTimeFormat("vi-VN", {
dateStyle: "short",
timeStyle: "medium",
});
function updateClock() {
const el = document.getElementById("current-time");
if (el) el.textContent = formatter.format(new Date());
}
Cách này tự xử lý thứ tự ngày tháng, dấu phân cách và cả múi giờ. Tạo formatter một lần bên ngoài hàm vì việc khởi tạo khá tốn kém, không nên lặp lại mỗi giây.
Muốn cố định múi giờ Việt Nam bất kể máy người dùng đặt ở đâu, thêm tùy chọn:
const formatter = new Intl.DateTimeFormat("vi-VN", {
dateStyle: "short",
timeStyle: "medium",
timeZone: "Asia/Ho_Chi_Minh",
});
Một lưu ý về độ chính xác
setInterval không đảm bảo chạy đúng từng mili giây. Khi tab bị ẩn, trình duyệt sẽ giãn nhịp gọi lại để tiết kiệm pin, nên đồng hồ có thể lệch. Với đồng hồ hiển thị thì không sao vì mỗi lần chạy đều đọc lại new Date(). Nhưng nếu bạn định dùng cách này để đếm ngược tới một mốc thời gian thì đừng cộng dồn từng giây, hãy luôn tính hiệu số giữa thời điểm đích và Date.now().