能以 for...of 依序讀取 iterable 的值,不把值與 index 混淆。
- 為什麼重要
- 以錯誤迴圈讀到 index 或 inherited key,會讓畫面顯示 0、1、2 而不是服務名稱。
- 完成條件
- 迭代三個服務物件並收集 name。
- 成功狀態
- iterations=3、values=規劃/設計/上線,且輸出順序等於原陣列。
- 證據位置
- iterations=3、values 順序正確
LESSON-15 · 自主延伸
把「陣列查找、複製與排序」拆成 4 個可獨立完成、可重設、可驗證的自主學習 module。
成果:完成可逐筆顯示、查找、判斷並安全排序的服務資料流程。
需要的檔案:files/starter/index.html(整合起點,保留跨 module 的最小缺口。)
完成後:完成可逐筆顯示、查找、判斷並安全排序的服務資料流程。
逐項展開;答不出來時先走補救連結,不必硬做。
自我檢查:我能否開啟 Elements、Console 或 Network 並找到本頁?
每一個目標只對應一個 module;成功狀態必須能指出證據。
依序展開;每次只改一項,操作後確認該模組自己的 DOM、progress 與 evidence。
白話:for...of 每一圈拿到的是目前那一筆值。
正式說法:for...of 對 iterable protocol 產生的 values 執行 statement,不直接提供索引。
何時使用:需要依序處理陣列、字串或其他 iterable,且不需要 index 時。
修改前後:Before:for...in 顯示 0/1/2。After:for...of 顯示三個服務名稱。
常見混淆:for...in 迭代 enumerable property keys;for...of 迭代 values。
情境:服務清單畫面顯示 0、1、2。
起始狀態:輸出尚無值,範例誤用 property keys。
目前主題:for...of
預期:iterations=3、values=規劃/設計/上線,且輸出順序等於原陣列。
證據:iterations=3、values 順序正確
第一個檢查:先印出每圈變數,確認是 key 還是 value。
重設:清空輸出並恢復三筆原始資料。
本模組官方來源:MDN|for...of
白話:find 拿回第一筆資料;some 只回答有或沒有。
正式說法:find 回傳第一個 predicate truthy 的 element 或 undefined;some 回傳是否至少一個 element 通過 predicate 的 Boolean。
何時使用:需要實際物件時用 find;只需判斷條件存在時用 some。
修改前後:Before:對 some 結果讀 id。After:物件與 Boolean 契約分開。
常見混淆:filter 會回傳所有符合項目的新陣列,不是第一筆或 Boolean。
情境:程式對 true.id 讀值而拋錯。
起始狀態:同一變數同時被當物件與 Boolean。
目前主題:find() 與 some()
預期:foundId=s2、exists=true、foundType=object、existsType=boolean。
證據:foundId=s2、exists=true、type 分別 object/boolean
第一個檢查:先問呼叫端需要資料本身還是只需要答案。
重設:恢復三筆服務與 featured 條件。
本模組官方來源:MDN|Array.find()
白話:解構拿出要用欄位;spread 先複製外層再覆蓋一個值。
正式說法:object destructuring binding 依 property 取值;object spread 建立 enumerable own properties 的淺層副本。
何時使用:從資料物件讀少數欄位,或建立不修改原外層物件的新版本。
修改前後:Before:service.price 直接被改。After:原物件與副本價格可並列。
常見混淆:spread 是 shallow copy,巢狀物件參照仍共享。
情境:排序/編輯一張卡片後原始 API 資料也改了。
起始狀態:只有原始 service,尚無副本。
目前主題:destructuring 與 spread copy
預期:copy!==original、original.price=1000、copy.price=1200、id/name 正確。
證據:sameReference=false、原價1000、副本1200
第一個檢查:先用 === 比較原物件與副本參照。
重設:恢復原始 price=1000。
本模組官方來源:MDN|Destructuring
白話:sort 會直接重排手上的陣列;先複製才不會動到原資料。
正式說法:Array.prototype.sort() sorts elements in place and returns the same array reference。
何時使用:需要顯示排序結果但仍要保留 API/初始順序時。
修改前後:Before:排序後重設無法回原序。After:原陣列與排序副本並存。
常見混淆:toSorted 會回傳新陣列,但本課技術邊界先用 spread + sort。
情境:按價格排序後,取消排序仍回不去原始順序。
起始狀態:原陣列順序 b,a,c。
目前主題:sort() 會修改原陣列
預期:original=b,a,c、sorted=a,b,c、sameReference=false。
證據:original 未變、sorted 已排序、sameReference=false
第一個檢查:排序前先保存原順序與參照比較。
重設:恢復原陣列並丟棄排序副本。
本模組官方來源:MDN|Array.sort()
情境:在同一份章節作品中整合 4 個 module,排除單項通過但組合失敗的問題。
交付:完成可逐筆顯示、查找、判斷並安全排序的服務資料流程。
檔案:files/starter/index.html 定位:#observe
操作:逐項讀取 outcomes,執行一次現況操作。
// OBSERVE:不修改程式,先記錄第一個失敗 moduleId。預期:能指出第一個未通過 module。
證據:第一個 moduleId 與缺少的 evidence。
原因:先觀察可避免未重現就直接改答案。
卡住先查:確認開啟的是 files/starter/index.html。
檔案:files/starter/index.html 定位:#modify
操作:以 for...of 依序收集三個 service.name。 → 以同一 predicate 執行 find/some 並比較回傳型別。 → 解構 id/name,再以 spread 建立新價格副本。 → 記錄原順序,spread 複製後排序,最後比較參照與兩個順序。
// 15-01-for-of: 以 for...of 依序收集三個 service.name。
// 15-02-find-some: 以同一 predicate 執行 find/some 並比較回傳型別。
// 15-03-destructuring-spread-copy: 解構 id/name,再以 spread 建立新價格副本。
// 15-04-sort: 記錄原順序,spread 複製後排序,最後比較參照與兩個順序。預期:完成可逐筆顯示、查找、判斷並安全排序的服務資料流程。
證據:iterations=3、values 順序正確;foundId=s2、exists=true、type 分別 object/boolean;sameReference=false、原價1000、副本1200;original 未變、sorted 已排序、sameReference=false
原因:逐項整合能把回歸定位到明確 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。
拆小:在「陣列查找、複製與排序」先完成第一個尚未通過的 module:for...of,不同時修改其他責任。
串接:依 15-01-for-of → 15-02-find-some → 15-03-destructuring-spread-copy → 15-04-sort 核對各自輸入與證據。
完整解答與原因:依序執行 以 for...of 依序收集三個 service.name。 → 以同一 predicate 執行 find/some 並比較回傳型別。 → 解構 id/name,再以 spread 建立新價格副本。 → 記錄原順序,spread 複製後排序,最後比較參照與兩個順序。;這個順序能把每個結果對回單一 module,避免整合後無法定位。
完整解答預設收合;先留下自己的嘗試,再開第三層。