JavaScript 實戰:陣列操作從入門到精通
各位好!
這篇是 JavaScript 系列的第五單元,我們要深入學習陣列(Array)的操作。陣列是處理多筆資料的基礎,掌握陣列方法是成為優秀開發者的關鍵。
什麼是陣列?
陣列是一個有序的資料集合,可以儲存多個值。
// 建立陣列
const fruits = ["蘋果", "香蕉", "橘子"];
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "文字", true, null, { name: "物件" }];
// 空陣列
const empty = [];
// 使用 Array 建構子(較少用)
const arr = new Array(1, 2, 3);
存取陣列元素
const fruits = ["蘋果", "香蕉", "橘子", "芒果"];
// 索引從 0 開始
console.log(fruits[0]); // "蘋果"(第一個)
console.log(fruits[1]); // "香蕉"(第二個)
console.log(fruits[3]); // "芒果"(第四個)
// 最後一個元素
console.log(fruits[fruits.length - 1]); // "芒果"
// 不存在的索引回傳 undefined
console.log(fruits[10]); // undefined
// 修改元素
fruits[1] = "草莓";
console.log(fruits); // ["蘋果", "草莓", "橘子", "芒果"]
// 陣列長度
console.log(fruits.length); // 4
基本陣列方法
新增與移除元素
const arr = [1, 2, 3];
// push:在尾端新增(回傳新長度)
arr.push(4);
arr.push(5, 6);
console.log(arr); // [1, 2, 3, 4, 5, 6]
// pop:移除尾端元素(回傳被移除的元素)
const last = arr.pop();
console.log(last); // 6
console.log(arr); // [1, 2, 3, 4, 5]
// unshift:在開頭新增
arr.unshift(0);
console.log(arr); // [0, 1, 2, 3, 4, 5]
// shift:移除開頭元素
const first = arr.shift();
console.log(first); // 0
console.log(arr); // [1, 2, 3, 4, 5]
// splice:插入、刪除或取代元素
const numbers = [1, 2, 3, 4, 5];
// 從索引 2 刪除 1 個元素
numbers.splice(2, 1);
console.log(numbers); // [1, 2, 4, 5]
// 從索引 1 刪除 0 個,插入 "a", "b"
numbers.splice(1, 0, "a", "b");
console.log(numbers); // [1, "a", "b", 2, 4, 5]
// 從索引 0 刪除 2 個,替換成 "x"
numbers.splice(0, 2, "x");
console.log(numbers); // ["x", "b", 2, 4, 5]
尋找元素
const fruits = ["蘋果", "香蕉", "橘子", "香蕉"];
// indexOf:找第一個符合的索引(沒找到回傳 -1)
console.log(fruits.indexOf("香蕉")); // 1
console.log(fruits.indexOf("芒果")); // -1
// lastIndexOf:找最後一個符合的索引
console.log(fruits.lastIndexOf("香蕉")); // 3
// includes:檢查是否包含(回傳布林值)
console.log(fruits.includes("蘋果")); // true
console.log(fruits.includes("芒果")); // false
// find:找第一個符合條件的元素
const numbers = [1, 5, 10, 15, 20];
const found = numbers.find(n => n > 10);
console.log(found); // 15
// findIndex:找第一個符合條件的索引
const index = numbers.findIndex(n => n > 10);
console.log(index); // 3
合併與分割
// concat:合併陣列(不改變原陣列)
const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = arr1.concat(arr2);
console.log(merged); // [1, 2, 3, 4]
// 展開運算子(更常用)
const merged2 = [...arr1, ...arr2];
console.log(merged2); // [1, 2, 3, 4]
// slice:複製部分陣列(不改變原陣列)
const numbers = [1, 2, 3, 4, 5];
const sliced = numbers.slice(1, 4); // 從索引 1 到 4(不包含 4)
console.log(sliced); // [2, 3, 4]
console.log(numbers); // [1, 2, 3, 4, 5](原陣列不變)
// 複製整個陣列
const copy = numbers.slice();
// join:轉成字串
const words = ["Hello", "World"];
console.log(words.join(" ")); // "Hello World"
console.log(words.join("-")); // "Hello-World"
// split:字串轉陣列(字串方法)
const text = "apple,banana,orange";
const arr = text.split(",");
console.log(arr); // ["apple", "banana", "orange"]
重要的迭代方法
forEach:遍歷陣列
const fruits = ["蘋果", "香蕉", "橘子"];
// 基本用法
fruits.forEach(fruit => {
console.log(fruit);
});
// 有索引參數
fruits.forEach((fruit, index) => {
console.log(`${index}: ${fruit}`);
});
// 0: 蘋果
// 1: 香蕉
// 2: 橘子
// 有陣列本身參數
fruits.forEach((fruit, index, array) => {
console.log(`${index + 1}/${array.length}: ${fruit}`);
});
map:轉換陣列
// 回傳新陣列,元素是經過函式處理的結果
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
const squared = numbers.map(n => n ** 2);
console.log(squared); // [1, 4, 9, 16, 25]
// 物件陣列的轉換
const users = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 35 }
];
const names = users.map(user => user.name);
console.log(names); // ["Alice", "Bob", "Charlie"]
const withGreeting = users.map(user => ({
...user,
greeting: `Hello, I'm ${user.name}`
}));
console.log(withGreeting);
// [
// { name: "Alice", age: 25, greeting: "Hello, I'm Alice" },
// { name: "Bob", age: 30, greeting: "Hello, I'm Bob" },
// { name: "Charlie", age: 35, greeting: "Hello, I'm Charlie" }
// ]
filter:過濾陣列
// 回傳符合條件的元素組成的新陣列
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4, 6, 8, 10]
const greaterThan5 = numbers.filter(n => n > 5);
console.log(greaterThan5); // [6, 7, 8, 9, 10]
// 物件陣列的過濾
const users = [
{ name: "Alice", age: 25, active: true },
{ name: "Bob", age: 30, active: false },
{ name: "Charlie", age: 35, active: true }
];
const activeUsers = users.filter(user => user.active);
console.log(activeUsers);
// [
// { name: "Alice", age: 25, active: true },
// { name: "Charlie", age: 35, active: true }
// ]
const adults = users.filter(user => user.age >= 30);
console.log(adults);
// [
// { name: "Bob", age: 30, active: false },
// { name: "Charlie", age: 35, active: true }
// ]
reduce:歸納陣列
// 將陣列歸納成單一值
const numbers = [1, 2, 3, 4, 5];
// 計算總和
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // 15
// 計算乘積
const product = numbers.reduce((acc, n) => acc * n, 1);
console.log(product); // 120
// 找最大值
const max = numbers.reduce((acc, n) => n > acc ? n : acc);
console.log(max); // 5
// 計算出現次數
const fruits = ["蘋果", "香蕉", "蘋果", "橘子", "香蕉", "蘋果"];
const count = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
console.log(count); // { 蘋果: 3, 香蕉: 2, 橘子: 1 }
// 扁平化巢狀陣列
const nested = [[1, 2], [3, 4], [5]];
const flat = nested.reduce((acc, arr) => acc.concat(arr), []);
console.log(flat); // [1, 2, 3, 4, 5]
some 和 every:檢查條件
const numbers = [1, 2, 3, 4, 5];
// some:至少一個符合條件
const hasEven = numbers.some(n => n % 2 === 0);
console.log(hasEven); // true
const hasNegative = numbers.some(n => n < 0);
console.log(hasNegative); // false
// every:全部符合條件
const allPositive = numbers.every(n => n > 0);
console.log(allPositive); // true
const allEven = numbers.every(n => n % 2 === 0);
console.log(allEven); // false
// 實用範例:表單驗證
const formFields = [
{ name: "username", value: "john", required: true },
{ name: "email", value: "[email protected]", required: true },
{ name: "phone", value: "", required: false }
];
const allRequiredFilled = formFields
.filter(field => field.required)
.every(field => field.value.trim() !== "");
console.log(allRequiredFilled); // true
排序與反轉
// sort:排序(會改變原陣列)
const numbers = [3, 1, 4, 1, 5, 9, 2, 6];
// 預設按字串排序
numbers.sort();
console.log(numbers); // [1, 1, 2, 3, 4, 5, 6, 9]
// 數字排序需要提供比較函式
const nums = [10, 5, 40, 25, 1000, 1];
// 升序
nums.sort((a, b) => a - b);
console.log(nums); // [1, 5, 10, 25, 40, 1000]
// 降序
nums.sort((a, b) => b - a);
console.log(nums); // [1000, 40, 25, 10, 5, 1]
// 字串排序
const words = ["banana", "apple", "cherry", "date"];
words.sort();
console.log(words); // ["apple", "banana", "cherry", "date"]
// 物件陣列排序
const users = [
{ name: "Charlie", age: 35 },
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 }
];
users.sort((a, b) => a.age - b.age);
console.log(users);
// [
// { name: "Alice", age: 25 },
// { name: "Bob", age: 30 },
// { name: "Charlie", age: 35 }
// ]
// reverse:反轉陣列(會改變原陣列)
const arr = [1, 2, 3, 4, 5];
arr.reverse();
console.log(arr); // [5, 4, 3, 2, 1]
實戰練習
練習 1:統計與分析
const scores = [85, 92, 78, 95, 88, 76, 91];
// 平均分數
const average = scores.reduce((sum, score) => sum + score, 0) / scores.length;
console.log(`平均:${average.toFixed(2)}`); // 86.43
// 最高分
const highest = Math.max(...scores);
console.log(`最高:${highest}`); // 95
// 最低分
const lowest = Math.min(...scores);
console.log(`最低:${lowest}`); // 76
// 及格人數
const passCount = scores.filter(score => score >= 60).length;
console.log(`及格人數:${passCount}`); // 7
練習 2:購物車計算
const cart = [
{ name: "商品 A", price: 100, quantity: 2 },
{ name: "商品 B", price: 200, quantity: 1 },
{ name: "商品 C", price: 50, quantity: 3 }
];
// 計算總價
const total = cart.reduce((sum, item) => {
return sum + (item.price * item.quantity);
}, 0);
console.log(`總價:${total} 元`); // 550 元
// 取得所有商品名稱
const productNames = cart.map(item => item.name);
console.log(productNames); // ["商品 A", "商品 B", "商品 C"]
// 找出最貴的商品
const mostExpensive = cart.reduce((max, item) => {
return item.price > max.price ? item : max;
});
console.log(`最貴:${mostExpensive.name}`); // "商品 B"
練習 3:資料轉換
const students = [
{ id: 1, name: "Alice", grade: 85 },
{ id: 2, name: "Bob", grade: 92 },
{ id: 3, name: "Charlie", grade: 78 }
];
// 轉換成以 id 為 key 的物件
const studentMap = students.reduce((map, student) => {
map[student.id] = student;
return map;
}, {});
console.log(studentMap);
// {
// 1: { id: 1, name: "Alice", grade: 85 },
// 2: { id: 2, name: "Bob", grade: 92 },
// 3: { id: 3, name: "Charlie", grade: 78 }
// }
// 新增等級欄位
const withLevel = students.map(student => ({
...student,
level: student.grade >= 90 ? "A" : student.grade >= 80 ? "B" : "C"
}));
console.log(withLevel);
練習 4:去重與分組
const data = [1, 2, 3, 2, 4, 1, 5, 3, 6];
// 去除重複
const unique = [...new Set(data)];
console.log(unique); // [1, 2, 3, 4, 5, 6]
// 分成奇數和偶數
const grouped = data.reduce((result, num) => {
const key = num % 2 === 0 ? "even" : "odd";
if (!result[key]) {
result[key] = [];
}
result[key].push(num);
return result;
}, {});
console.log(grouped);
// { odd: [1, 3, 1, 5, 3], even: [2, 2, 4, 6] }
鏈式呼叫
多個陣列方法可以連續呼叫。
const users = [
{ name: "Alice", age: 25, active: true },
{ name: "Bob", age: 30, active: false },
{ name: "Charlie", age: 35, active: true },
{ name: "David", age: 28, active: true },
{ name: "Eve", age: 32, active: false }
];
// 找出活躍用戶的平均年齡
const avgAge = users
.filter(user => user.active)
.map(user => user.age)
.reduce((sum, age) => sum + age, 0) /
users.filter(user => user.active).length;
console.log(avgAge); // 29.33
// 取得活躍用戶名單(按年齡排序)
const activeNames = users
.filter(user => user.active)
.sort((a, b) => a.age - b.age)
.map(user => user.name);
console.log(activeNames); // ["Alice", "David", "Charlie"]
效能考量
// 不好:多次遍歷
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = doubled.filter(n => n % 2 === 0);
const sum = evens.reduce((acc, n) => acc + n, 0);
// 好:一次遍歷
const result = numbers.reduce((acc, n) => {
const doubled = n * 2;
if (doubled % 2 === 0) {
return acc + doubled;
}
return acc;
}, 0);
// 但在大多數情況下,可讀性比效能更重要
// 除非處理大量資料,否則多次遍歷的影響不大
小結
這篇我們學習了:
- 陣列的建立與存取
- 基本陣列方法:push、pop、shift、unshift、splice
- 尋找方法:indexOf、find、includes
- 重要迭代方法:forEach、map、filter、reduce
- 排序與反轉
- 實戰應用與鏈式呼叫
下一步:
完成這篇後,你已經能夠: - 靈活操作陣列資料 - 使用現代陣列方法處理資料 - 撰寫簡潔高效的資料處理程式碼
前往下一篇:單元六:物件與解構
在那裡,我們會學習如何處理結構化資料。
0 留言
發表留言