Home
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

4

Local AI

--

Uedu Code

--

Taipei AQI 57 · Taichung AQI 74 · Tainan AQI 63 · Kaohsiung AQI 64
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 14

時間與計時器

Date 物件、setTimeout、setInterval 與事件迴圈
Interaction實作 20 minute(s)

Learning Objectives

  • 用 new Date 建立日期,並用 getFullYear、getMonth、getDate、getDay 取得年月日與星期
  • 說明月份從 0 開始,以及時間戳記(從 1970 年起算的毫秒數)
  • 用 setTimeout 延遲執行一次,用 clearTimeout 取消
  • 用 setInterval 重複執行,用 clearInterval 停止
  • 說明計時器的 callback 要等同步程式跑完才會執行

Date:處理日期與時間

JavaScript 用 Date 物件表示一個時間點。建立的方式:

寫法 得到
new Date() 現在
new Date(2019, 11, 25) 2019 年 12 月 25 日 0 點(本地時間):依序是年、月、日、時、分、秒、毫秒,沒寫的是 0(日是 1)
new Date(0) 1970-01-01 00:00:00 UTC 之後 0 毫秒
new Date('2019-12-25T10:30:00') 依字串解析;格式建議用 ISO 格式(年-月-日T時:分:秒)

月份從 0 開始:0 是一月、11 是十二月。這是最常出錯的地方,顯示給人看時記得 getMonth() + 1。 超出範圍的值會自動進位:new Date(2019, 12, 25) 是 2020 年 1 月 25 日。

方法 回傳
getFullYear() 四位數的年
getMonth() 月,0~11
getDate() 日,1~31
getDay() 星期幾,0 是星期日、6 是星期六
getHours()、getMinutes()、getSeconds() 時、分、秒
setFullYear(y)、setDate(d)、setHours(h)… 修改;超出範圍會自動進位到下個月或下一年

這些方法使用瀏覽器所在地的時區(本地時間)。另外有一組 getUTCFullYear()、getUTCHours()… 使用世界標準時間(UTC)。

建立日期與取得年月日

new Date(2019, 11, 25) 的 11 代表十二月。注意第 3 行印出的月份是 11,第 7 行組字串時要加 1 才是我們習慣的 12 月。

時間戳記

電腦內部用一個數字記錄 Date:從 1970 年 1 月 1 日 00:00:00 UTC 到這個時間點的毫秒數,叫做時間戳記(timestamp)。

寫法 意思
Date.now() 現在的時間戳記
d.getTime() 這個 Date 的時間戳記
Date.UTC(2026, 9, 29) 指定 UTC 時間的時間戳記(月份一樣從 0 開始)
d2 - d1 兩個 Date 相減,得到相差的毫秒數
d.toISOString() 轉成 ISO 格式的 UTC 字串,例如 2026-10-29T06:30:00.000Z

用時間戳記可以計算經過的時間:一天是 1000 * 60 * 60 * 24 毫秒。

Date 是物件,=== 比的是不是同一個物件;比較兩個時間點要比 getTime()。

逐步執行動畫裡的「現在」是固定的虛擬時間(台北時間 2026-10-29 14:30,也就是 UTC 06:30),所以每次播放結果都一樣。 範例用 toISOString() 以 UTC 顯示時間,不管你在哪個時區看都相同。在真正的瀏覽器裡,new Date() 是你電腦的現在時間。

時間戳記與時間的計算

第 4 行用兩個時間戳記相減,算出 10 月 1 日到 29 日相差幾毫秒,再換成天數。最後一段兩個 Date 表示同一個時間,=== 卻是 false。

想一想:Date

1.

下面的程式會印出什麼?

const d = new Date(2026, 2, 8);
console.log(d.getMonth(), d.getDate());
2.

下面的程式會印出什麼?

const d = new Date(2026, 0, 31);
d.setDate(d.getDate() + 1);
console.log(d.getMonth() + 1, d.getDate());
3.

getDay() 回傳 0 代表什麼?

第 1 次作答

setTimeout:過一段時間執行一次

const id = setTimeout(callback, 毫秒, 要傳給 callback 的引數…);
clearTimeout(id);   // 時間還沒到之前取消
  • setTimeout 設定好計時器之後馬上結束,不會停在那裡等;程式繼續往下執行
  • 時間到了,callback 才被執行,而且只執行一次
  • 回傳一個編號(正整數),把它交給 clearTimeout 可以取消還沒執行的計時器
  • 延遲寫 0 也不會立刻執行:callback 一定要等目前的同步程式全部跑完才輪得到它

最後一點是 JavaScript 執行模型的核心,叫做事件迴圈(event loop):瀏覽器在背景計時,時間到了就把 callback 放進「工作佇列」排隊; 等呼叫堆疊上的程式都執行完,事件迴圈才從佇列裡拿出下一件工作來執行。下面的小工具一步一步示範這個過程。

投影片也寫了字串的寫法 setTimeout("alert('Hello')", 3000):它會像 eval 一樣執行字串,容易出錯也有安全疑慮,請一律傳入函式。

事件迴圈:setTimeout(…, 0) 也要排隊

程式只有五行:印出「1. 開始」、設定延遲 0 毫秒的計時器、印出「2. 結束」。按「下一步」一步一步看:callback 什麼時候進入工作佇列?為什麼「3. 計時器」最後才印出?

setTimeout 的執行順序與 clearTimeout

程式設定了三個計時器:3 秒、2 秒、0 毫秒。同步程式(第 2~15 行)先全部跑完,計時器的 callback 才依時間順序執行。2 秒的計時器取消了 3 秒的那一個,所以「Hello」不會出現。

用迴圈設定多個計時器

投影片的練習:每秒印出 0、1、2、3。迴圈本身一瞬間就跑完了,只是設定了延遲 0、1000、2000、3000 毫秒的四個計時器。每個 callback 印出虛擬時間的時、分、秒(UTC):每次相差一秒。

setInterval:每隔一段時間執行

const id = setInterval(callback, 毫秒);
clearInterval(id);   // 停止

setInterval 每隔指定的時間就執行一次 callback,直到 clearInterval 才停止;忘了清除,它會一直執行下去。

另一種做法是在 setTimeout 的 callback 裡再設定下一次 setTimeout(投影片 Lab01 的作法)。兩者的差別: setInterval 依固定的間隔排進佇列,不管上一次花了多久;鏈式的 setTimeout 等這一次執行完才開始算下一次的時間。

計時器不保證準時:間隔是「最少」要等多久,如果這時候還有其他程式在執行,callback 就要繼續排隊。 所以碼表、倒數這類要準確顯示經過時間的程式,應該記下開始的時間,每次用 Date.now() - 開始時間 計算,而不是單純數執行了幾次。

逐步執行動畫的時間是虛擬的:計時器不會真的等待,而是依時間先後立刻執行,所以 1 秒、2 秒的計時器一下子就播完了。 範例印出的時間是虛擬時鐘的時間。下方的網頁沙箱則是真的瀏覽器,會照實際時間執行。

事件迴圈:setInterval 重複排隊

每隔 1000 毫秒,計時器就把 callback 放進工作佇列一次;第 3 次時 n === 3,clearInterval 把計時器移除。按到最後一步。

setInterval 與 clearInterval

同步程式先印出「計時開始」。之後 callback 每一秒執行一次,第 3 次時呼叫 clearInterval(id),就不再執行了。

用 setTimeout 做出重複

tick 每次執行時,如果還沒滿 3 次,就再設定一次一秒後的 setTimeout(tick, 1000)。

互動練習:碼表

這是真的瀏覽器,計時器會照實際時間執行。三個按鈕的事件處理函式已經寫好了(addEventListener 會在第 19 課詳細說明),請在大括號裡補上程式,改完按「執行」,再在預覽裡按按鈕試試看。

想一想:計時器

1.

下面的程式會印出什麼?

console.log('A');
setTimeout(() => console.log('B'), 0);
console.log('C');
2.

下面的程式會印出什麼?

const t = setTimeout(() => console.log('時間到'), 1000);
clearTimeout(t);
console.log('結束');
3.

下面的程式會印出什麼?

let n = 0;
const id = setInterval(() => {
  n += 2;
  if (n >= 6) {
    clearInterval(id);
    console.log(n);
  }
}, 500);
第 1 次作答

實作:日期格式化

完成 formatDate(d):回傳「年/月/日 星期幾」的字串,月與日都補成兩位數(用字串的 padStart(2, '0'))。例如 2026 年 1 月 5 日要顯示 2026/01/05 星期一。

你的輸出
預期輸出

重點精華回顧

  • new Date() 是現在,new Date(年, 月, 日, …) 指定時間;月份從 0 開始,getDay() 的 0 是星期日。
  • 超出範圍的值會自動進位:setDate(getDate() + 5) 可以跨月。
  • 時間戳記是從 1970-01-01 00:00:00 UTC 起算的毫秒數:Date.now()、getTime();兩個 Date 相減得到相差的毫秒。
  • setTimeout(fn, ms) 過一段時間執行一次,clearTimeout(id) 取消;setInterval(fn, ms) 重複執行,clearInterval(id) 停止。
  • 設定計時器不會讓程式停下來等;callback 要等目前的同步程式跑完,由事件迴圈從工作佇列取出執行,即使延遲是 0。
  • 計時器不保證準時;要準確計算經過的時間,用 Date.now() 相減。
這一課完成了!
Next lesson:取得與建立網頁元素
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。