JavaScript 實戰:陣列操作從入門到精通

2026-01-26 07:50 | By justin | JavaScript
(Updated: 2026-01-26 07:50)

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 留言

目前沒有留言

發表留言
回覆