能把比較結果交給 if...else 選出明確分支,不以字串內容猜真假。
- 為什麼重要
- 價格、庫存與表單狀態若使用錯誤 truthiness,會讓不該通過的輸入進入成功分支。
- 完成條件
- 以數值 1200 與門檻 1000 執行大於等於比較,再依 Boolean 分流。
- 成功狀態
- comparison=true、branch=eligible,且 inputType=number。
- 證據位置
- inputType=number、comparison=true、branch=eligible
LESSON-14 · 自主延伸
把「值、條件、scope 與函式責任」拆成 4 個可獨立完成、可重設、可驗證的自主學習 module。
成果:完成一個能安全轉換輸入、依條件計算並把副作用留在邊界的估價器。
需要的檔案:files/starter/index.html(整合起點,保留跨 module 的最小缺口。)
完成後:完成一個能安全轉換輸入、依條件計算並把副作用留在邊界的估價器。
逐項展開;答不出來時先走補救連結,不必硬做。
自我檢查:我能否開啟 Elements、Console 或 Network 並找到本頁?
每一個目標只對應一個 module;成功狀態必須能指出證據。
依序展開;每次只改一項,操作後確認該模組自己的 DOM、progress 與 evidence。
白話:先做出 true/false,再讓 if 決定要走哪一條路。
正式說法:比較運算式產生 Boolean;if 依條件的 truthy/falsy 結果執行互斥 statement branch。
何時使用:價格門檻、必填狀態、權限與任何二選一規則。
修改前後:Before:直接以字串 0 判斷。After:先轉成數值並留下 Boolean 與分支文字。
常見混淆:字串 false 與字串 0 都是 truthy,不等於 Boolean false 或數值 0。
情境:滿額提示把字串 0 誤判成已達門檻。
起始狀態:輸出尚無比較結果與分支。
目前主題:Boolean、比較與 if...else
預期:comparison=true、branch=eligible,且 inputType=number。
證據:inputType=number、comparison=true、branch=eligible
第一個檢查:先在 Console 看 typeof total,再看比較式。
重設:清空 output 並恢復 total=1200、threshold=1000。
本模組官方來源:MDN|if...else
白話:先把輸入轉成數字,再檢查它是不是轉換失敗的 NaN。
正式說法:Number() 執行數值強制轉型;Number.isNaN() 只在參數本身為 NaN 時回傳 true。
何時使用:數量、預算、價格與任何來自 input/dataset/query 的數值文字。
修改前後:Before:2 + 3 得到字串 23。After:轉型與 invalid 分支都可觀察。
常見混淆:全域 isNaN 會先強制轉型;Number.isNaN 不會把一般字串先當數字。
情境:預算 abc 被帶入總價,畫面顯示 NaN 元。
起始狀態:output 只顯示原始字串。
目前主題:型別轉換與 Number.isNaN()
預期:42 轉成 number 42;abc 轉成 NaN 且 invalid=true。
證據:validValue=42、invalidIsNaN=true、convertedType=number
第一個檢查:先記錄 typeof input.value,再執行 Number()。
重設:恢復有效值 42 與無效值 abc。
本模組官方來源:MDN|Number.isNaN()
白話:變數只能在宣告它的範圍和更裡面被看見。
正式說法:JavaScript 使用 lexical scope;let/const 具 block scope,function declaration/parameters 具 function scope。
何時使用:所有變數與函式設計,尤其事件處理器、迴圈與暫存狀態。
修改前後:Before:暫存值掛到 window。After:區塊外讀取會明確失敗且無全域污染。
常見混淆:scope 是名稱可見性;closure 是函式保留其建立時 lexical environment 的能力。
情境:兩個功能都使用 status 變數,後載入的程式覆蓋前一個。
起始狀態:測試尚未建立 lexical block。
目前主題:scope
預期:insideValue 可讀、outsideError=ReferenceError、globalLeak=false。
證據:insideValue=local、outsideError=ReferenceError、globalLeak=false
第一個檢查:先找宣告所在的最小大括號範圍。
重設:移除測試 global property 並重新執行。
本模組官方來源:MDN|Scope
白話:函式只算答案;拿到答案的人再決定要不要改畫面。
正式說法:純函式對相同輸入產生相同輸出且不改變外部可觀察狀態;DOM write 是副作用。
何時使用:價格、篩選、格式化等可獨立計算,再由事件或 render 邊界更新 UI。
修改前後:Before:calculate 同時 querySelector 與改文字。After:calculate 只 return,呼叫端更新 DOM 一次。
常見混淆:函式沒有 console.log 不代表純;修改輸入物件或外層變數也是副作用。
情境:估價函式在測試環境因找不到 DOM 而失敗。
起始狀態:計算與 output 更新混在同一函式。
目前主題:純函式與副作用
預期:first=second、inputUnchanged=true、domWrites=1。
證據:first=second、inputUnchanged=true、domWrites=1
第一個檢查:先列出函式除了 return 還修改了什麼。
重設:清空 output 並恢復原始輸入陣列。
本模組官方來源:MDN|Functions
情境:在同一份章節作品中整合 4 個 module,排除單項通過但組合失敗的問題。
交付:完成一個能安全轉換輸入、依條件計算並把副作用留在邊界的估價器。
檔案:files/starter/index.html 定位:#observe
操作:逐項讀取 outcomes,執行一次現況操作。
// OBSERVE:不修改程式,先記錄第一個失敗 moduleId。預期:能指出第一個未通過 module。
證據:第一個 moduleId 與缺少的 evidence。
原因:先觀察可避免未重現就直接改答案。
卡住先查:確認開啟的是 files/starter/index.html。
檔案:files/starter/index.html 定位:#modify
操作:以數值輸入執行比較,將 Boolean 交給 if...else 並顯示分支。 → 對 42 與 abc 各做一次 Number() 與 Number.isNaN()。 → 建立 block 變數,在內外各讀一次並檢查 window 是否洩漏同名值。 → 以相同輸入呼叫兩次純計算,確認輸入未變,再記錄單次 DOM write。
// 14-01-boolean-if-else: 以數值輸入執行比較,將 Boolean 交給 if...else 並顯示分支。
// 14-02-number-isnan: 對 42 與 abc 各做一次 Number() 與 Number.isNaN()。
// 14-03-scope: 建立 block 變數,在內外各讀一次並檢查 window 是否洩漏同名值。
// 14-04-topic: 以相同輸入呼叫兩次純計算,確認輸入未變,再記錄單次 DOM write。預期:完成一個能安全轉換輸入、依條件計算並把副作用留在邊界的估價器。
證據:inputType=number、comparison=true、branch=eligible;validValue=42、invalidIsNaN=true、convertedType=number;insideValue=local、outsideError=ReferenceError、globalLeak=false;first=second、inputUnchanged=true、domWrites=1
原因:逐項整合能把回歸定位到明確 module。
卡住先查:回到第一個未通過的 module,只修該處。
檔案:files/solution/index.html 定位:#verify
操作:重新整理並依 outcomes 順序重跑所有證據。
// VERIFY:逐項記錄 pass/fail,不以看到畫面代替 evidence。預期:4/4 module 通過。
證據:每個 moduleId 都有實際結果與重設後重現紀錄。
原因:單項通過不代表整合後沒有 selector、id 或狀態衝突。
卡住先查:若失敗,回到第一個失敗 module,不同時修多項。
檔案:files/starter/index.html 定位:#challenge
操作:替另一個商家情境重做,仍達成:完成一個能安全轉換輸入、依條件計算並把副作用留在邊界的估價器。
// CHALLENGE:只替換內容與資料,不新增框架或跳過 self-check。預期:完成一個能安全轉換輸入、依條件計算並把副作用留在邊界的估價器。
證據:轉用後的作品與全數 module self-check。
原因:能轉用才代表理解責任,而非只記住原範例。
卡住先查:先確認共同基底與 module id 未被改壞。
重設方法:重新載入 files/starter/index.html;若 localStorage 不可用,使用頁面內記憶狀態並提供重設按鈕。
挑戰:將同一組責任轉用到另一個商家情境,仍達成:完成一個能安全轉換輸入、依條件計算並把副作用留在邊界的估價器。
限制:不新增框架。;保留 module id 與驗收證據。
提交證據:提交可直接開啟的作品與逐項 self-check。
拆小:在「值、條件、scope 與函式責任」先完成第一個尚未通過的 module:Boolean、比較與 if...else,不同時修改其他責任。
串接:依 14-01-boolean-if-else → 14-02-number-isnan → 14-03-scope → 14-04-topic 核對各自輸入與證據。
完整解答與原因:依序執行 以數值輸入執行比較,將 Boolean 交給 if...else 並顯示分支。 → 對 42 與 abc 各做一次 Number() 與 Number.isNaN()。 → 建立 block 變數,在內外各讀一次並檢查 window 是否洩漏同名值。 → 以相同輸入呼叫兩次純計算,確認輸入未變,再記錄單次 DOM write。;這個順序能把每個結果對回單一 module,避免整合後無法定位。
完整解答預設收合;先留下自己的嘗試,再開第三層。