JAVASCRIPT V2 · FOUNDATIONS · 40
Arrays、Objects、References:從幾個變數進入真正的資料模型
真實程式很少只有一個 score。你會有很多學生,每個學生又有 id、name、score。這一課的重點不是一次背完所有 array methods,而是先理解資料形狀、index、property、identity、reference 與 mutation。完整的 map/filter/find/reduce mastery 會放在 Stage 2 的 58。
Learning outcomes
- 依資料問題選擇 Array、Object、Array of Objects。
- 正確讀寫 index、length 與 object properties。
- 區分 position(index) 與 identity(id)。
- 理解 object/array assignment 的 reference aliasing。
- 能用 loop + function 處理 Array of Objects。
1. Why now:五個學生不該變成十五個獨立變數
const name1 = "Amy";
const score1 = 92;
const name2 = "Bob";
const score2 = 58;
這種寫法無法自然擴充,也很難 loop。資料需要「一筆實體」與「多筆集合」兩個層級。
一個實體,多個命名欄位。
多筆同類資料,有順序。
2. Array basics:有順序的一串 values
const scores = [80, 90, 100];
console.log(scores[0]); // 80
console.log(scores.length); // 3
Array index 從 0 開始。length 是 element 數量,不是最後一個 index。
const last =
scores[scores.length - 1]; // 1003. Array mutation:同一個 array state 可以改變
const scores = [80, 90];
scores.push(100);
scores[0] = 85;
console.log(scores); // [85, 90, 100]
const 阻止的是 binding reassignment,不是阻止 array 內容 mutation。這正好呼應 36。
4. Object basics:用 property 名稱描述一個 entity
const student = {
id: 7,
name: "Anson",
score: 90
};
console.log(student.name);
student.score = 95;
Object 讓欄位有語意,不需要記「第二格代表姓名」。
5. Dot vs Bracket property access
student.name
student["name"]
const key = "score";
student[key]
已知固定 property name 時通常使用 dot notation;property name 來自變數時 bracket notation 很重要。
6. Worked Example A:Array of Objects 是常見 API 資料形狀
const students = [
{ id: 1, name: "Amy", score: 92 },
{ id: 2, name: "Bob", score: 58 },
{ id: 3, name: "Cara", score: 81 }
];
這種形狀會出現在 API JSON、database result、React list state。你應該能口頭描述:
students
= array
= 3 objects
= each object has id/name/score7. Position vs Identity:index 不是資料 ID
students[0] // 現在第一個位置的資料
student.id // 這筆資料自己的 identity
排序、filter、insert 後,某個 student 的 index 可能改變,但 id 通常仍用來辨認同一 entity。
這個區別到 React list key、database primary key 都非常重要。
8. Worked Example B:Loop + Object property
let total = 0;
for (const student of students) {
total += student.score;
}
const average =
students.length
? total / students.length
: 0;
這裡直接組合前面三課:loop、function/data rule、object property。
9. Reference aliasing:兩個名稱可能指向同一個 object
const original = { score: 80 };
const alias = original;
alias.score = 100;
console.log(original.score); // 100
alias = original 沒有自動 clone object。兩個 bindings 都能存取同一個 object,因此 mutation 從另一個名稱也看得到。
10. Worked Example C:Shallow copy 建立另一個 top-level object
const original = {
name: "Amy",
score: 80
};
const updated = {
...original,
score: 95
};
console.log(original.score); // 80
console.log(updated.score); // 95
Spread 在這裡建立新的 top-level object。完整的 shallow/deep copy、nested object 問題會在 Stage 2/Advanced 再展開。
11. 找不到資料時,左邊 expression 可能是 undefined
const item = students[99];
console.log(item); // undefined
如果接著寫:
students[99].name
// TypeError
真正要 debug 的不是 .name 拼字,而是「students[99] 到底回了什麼」。
12. map/filter/find 先 Preview,不在這一課塞完
students.map(student => student.name);
students.filter(student => student.score >= 60);
students.find(student => student.id === 2);
現在只要知道它們各自表達不同的 collection operation。58 會逐步拆 callback、return shape、mutation 與 chaining。這是 v2 的粒度原則:不要一頁同時要求初學者 mastery 太多 abstraction。
13. Common mistakes
A. 把 length 當最後 index
scores[scores.length] // undefined
B. 把 index 當永久 identity
排序後 index 改變,不能假設「第 0 筆永遠是 Amy」。
C. 誤以為 assignment 會 clone object
const b = a; // alias,不是 clone
D. 在不知道資料存在時直接讀 property
先確認左邊 expression 的 value。
14. Debug evidence:先印 shape
console.log({
isArray: Array.isArray(students),
length: students.length,
first: students[0]
});
console.table(students);
對陌生 API data,先確認「是不是 array、幾筆、第一筆有哪些 properties」,比直接猜 property path 有效。
15. Guided exercise:逐輪算 class average
const students = [
{ name: "A", score: 60 },
{ name: "B", score: 90 }
];
用 for...of 畫 trace:student、student.score、total before、total after。最後除以 students.length。
16. Independent exercise:實作 classAverage(students)
需求:
- input 是 Array of Objects。
- 每個 object 至少有
score。 - 空 array 回 0。
- 不可 hard-code 筆數。
classAverage([]) // 0
classAverage([
{score: 60},
{score: 90}
]) // 7517. Challenge:Alias bug
const a = { score: 80 };
const b = a;
b.score += 10;
先預測 a.score,再說明為什麼。如果你希望 b 是獨立 top-level object,要怎麼建立?
Project checkpoint:Grade Tracker Data Model
const students = [
{ id: 1, name: "Amy", score: 92 },
{ id: 2, name: "Bob", score: 58 },
{ id: 3, name: "Cara", score: 81 }
];
function classAverage(students) {
if (students.length === 0) return 0;
let total = 0;
for (const student of students) {
total += student.score;
}
return total / students.length;
}
Foundation 到這裡形成第一個完整鏈:value/type → condition → loop → function → data model。下一個 Stage 才進入常用 methods 與 modern syntax。
18. Vocabulary / Summary
- Array:有順序的 collection。
- index:目前位置。
- Object:以 property 描述 entity。
- property:object 上的命名資料。
- identity:辨識同一 entity 的穩定概念,常由 id 表達。
- reference/alias:多個 bindings 存取同一 object。
- mutation:改變既有 object/array 的內容。
19. Further reading
Knowledge check
- 解釋 array index 與 entity id 的差異。
- 說明
const b=a為什麼不是 object clone。 - 指出
scores[scores.length]為何是 undefined。 - 說明 Array of Objects 為何適合 API records。
- 完成
classAverage()mastery exercise並通過 empty/single/multiple tests。