Skip to content

บทที่ 07 — Array และการจัดการข้อมูล

← บทที่ 06 | สารบัญ | บทที่ 08: Strings + Regex + Date →

Array = รายการของข้อมูล — และการจัดการ array ด้วย map/filter/reduce คือทักษะที่ใช้บ่อยที่สุดในงานจริง

อ่านจบบทนี้คุณจะ:

  • จัดการ array ได้คล่อง — เพิ่ม ลบ ค้นหา
  • เข้าใจ map, filter, reduce อย่างลึกซึ้ง (3 ตัวนี้สำคัญที่สุด)
  • เขียน "data pipeline" — ต่อ method หลายตัวเข้าด้วยกัน
  • รู้จัก array methods ที่ใช้บ่อยทั้งหมด

ใช้เวลา 3 ชั่วโมง


Part 1: Array พื้นฐาน

1.1 Array คืออะไร

Array = รายการของข้อมูล เรียงตามลำดับ เข้าถึงด้วยตำแหน่ง (index)

javascript
const fruits = ["แอปเปิล", "กล้วย", "ส้ม"];

จุดสำคัญ — index เริ่มนับจาก 0 ไม่ใช่ 1:

javascript
fruits[0]            // "แอปเปิล" — ตัวแรก
fruits[1]            // "กล้วย"   — ตัวที่สอง
fruits[2]            // "ส้ม"     — ตัวที่สาม
fruits[3]            // undefined — ไม่มีตัวที่ 4

fruits.length        // 3 — จำนวนสมาชิก
fruits[fruits.length - 1]   // "ส้ม" — ตัวสุดท้าย
fruits.at(-1)        // "ส้ม" — วิธีใหม่ ใช้ index ติดลบได้

array.at(-1) เป็นวิธีสมัยใหม่ที่อ่านง่ายกว่า array[array.length - 1] สำหรับเอาตัวท้าย

1.2 Array เก็บอะไรก็ได้

javascript
const mixed = [1, "ข้อความ", true, null, { name: "Alice" }, [1, 2]];

แต่ในงานจริง — array ควรเก็บข้อมูล "ชนิดเดียวกัน" (เช่น array ของตัวเลขทั้งหมด, array ของ user object ทั้งหมด) เพื่อให้จัดการง่าย

1.3 สร้าง Array

javascript
const a = [1, 2, 3];                              // ตรง ๆ (ใช้บ่อยสุด)
const b = Array.from("abc");                       // จาก string → ["a","b","c"]
// เดี๋ยวจะเห็น (_, i) => ... โดย _ ไม่ใช่ syntax พิเศษของ JS แค่เป็นชื่อตัวแปรธรรมดา
// ที่โปรแกรมเมอร์ตกลงกันเป็น convention ว่า "ตัวแปรนี้รับมาแต่ไม่ใช้" — ตรงนี้แค่ต้องการ i (ตำแหน่ง) เท่านั้น
const c = Array.from({ length: 5 }, (_, i) => i);  // [0,1,2,3,4]
const d = new Array(3).fill(0);                    // [0, 0, 0]

Array.from({ length: n }, (_, i) => ...) เป็นเทคนิคสร้าง array ขนาด n ที่มีประโยชน์


Part 2: เพิ่ม / ลบ สมาชิก

2.1 Methods ที่ "แก้ของเดิม" (mutating)

methods กลุ่มนี้ เปลี่ยน array เดิม (mutating = แก้ของเดิม):

javascript
const arr = [1, 2, 3];

arr.push(4);          // เพิ่มท้าย → [1, 2, 3, 4]
arr.pop();            // ลบท้าย → [1, 2, 3] (คืนค่าที่ลบ: 4)
arr.unshift(0);       // เพิ่มหน้า → [0, 1, 2, 3]
arr.shift();          // ลบหน้า → [1, 2, 3] (คืนค่าที่ลบ: 0)

splice — เพิ่ม/ลบ ตรงกลาง:

javascript
const arr = [1, 2, 3, 4, 5];
arr.splice(1, 2);              // ลบ 2 ตัว เริ่มจาก index 1 → [1, 4, 5]
arr.splice(1, 0, "a", "b");    // เพิ่ม "a","b" ที่ index 1 (ลบ 0 ตัว)

sort และ reverse — ก็แก้ array เดิม:

javascript
const arr = [3, 1, 2];
arr.sort();           // [1, 2, 3] — แต่ระวัง! (Part 8.1) — แก้ array เดิม! ใช้ toSorted() ถ้าไม่อยากแก้
arr.reverse();        // กลับลำดับ — แก้ array เดิม! ใช้ toReversed() ถ้าไม่อยากแก้

2.2 Methods ที่ "ไม่แก้ของเดิม" (non-mutating)

💡 เราเรียน mutating methods ก่อนเพื่อให้เข้าใจพื้นฐาน แต่ในงานจริงแนะนำให้ใช้ non-mutating เป็นหลัก — เพราะปลอดภัยกว่าและคาดเดาได้ง่ายกว่า

JavaScript สมัยใหม่ (ES2023) มี methods ที่ไม่แก้ของเดิม — สร้างใหม่แทน:

javascript
const arr = [3, 1, 2];

const sorted = arr.toSorted();        // [1, 2, 3] — arr เดิมไม่เปลี่ยน
const reversed = arr.toReversed();
const updated = arr.with(0, 99);       // เปลี่ยน index 0 เป็น 99 → array ใหม่

📦 ต้องการเวอร์ชันไหน: toSorted/toReversed/with เป็น ES2023 — รัน Node.js 20+, Chrome 110+, Firefox 115+, Safari 16+ ขึ้นไปถึงจะมี ถ้าโปรเจกต์ยังต้องรองรับเบราว์เซอร์/Node เก่ากว่านั้น ใช้สำนวน copy ก่อนค่อย mutate แทน เช่น [...arr].sort(), [...arr].reverse()

💡 ทำไม non-mutating ดี: การ "แก้ของเดิม" ทำให้เกิดบั๊ก (จำเรื่อง reference จากบทที่ 02 ได้ไหม — ถ้ามีหลายที่ชี้ array เดียวกัน แก้ที่หนึ่งกระทบหมด) — การ "สร้างใหม่" ปลอดภัยกว่า โค้ดคาดเดาได้ → งานสมัยใหม่นิยม non-mutating


Part 3: ค้นหาข้อมูลใน Array

javascript
const nums = [10, 20, 30, 40, 50];

nums.includes(30)              // true — มี 30 ไหม
nums.indexOf(30)               // 2 — 30 อยู่ตำแหน่งไหน (ไม่เจอคืน -1)

nums.find(n => n > 25)         // 30 — ตัวแรกที่เข้าเงื่อนไข
nums.findIndex(n => n > 25)    // 2 — index ของตัวแรกที่เข้าเงื่อนไข

nums.some(n => n > 45)         // true — มีอย่างน้อย 1 ตัวที่ > 45 ไหม
nums.every(n => n > 5)         // true — ทุกตัว > 5 ไหม

อธิบาย:

  • includes / indexOf — หาด้วย "ค่า" ตรง ๆ
  • find / findIndex — หาด้วย "เงื่อนไข" (ส่ง function เข้าไป)
  • some — "มีบางตัวไหม" / every — "ทุกตัวไหม"

Part 4: map — แปลงทุกตัว

map คือ method ที่ใช้บ่อยที่สุด — "แปลงทุกตัวใน array เป็นค่าใหม่ ได้ array ใหม่ที่ยาวเท่าเดิม"

4.1 พื้นฐาน

javascript
const numbers = [1, 2, 3, 4];

const doubled = numbers.map(n => n * 2);
console.log(doubled);          // [2, 4, 6, 8]
console.log(numbers);          // [1, 2, 3, 4] — ของเดิมไม่เปลี่ยน

อธิบาย: map รับ function เข้าไป — มันเรียก function นั้นกับสมาชิกทุกตัว — แล้วเก็บผลลัพธ์เป็น array ใหม่

ลองคิดทีละขั้น:

text
[1, 2, 3, 4]
 ↓  ↓  ↓  ↓     แต่ละตัวผ่าน n => n * 2
[2, 4, 6, 8]

4.2 ตัวอย่างใช้จริง

งานที่เจอบ่อยสุดของ map คือ "แปลงรูปข้อมูล" — เช่นมี array ของ object ผู้ใช้ แล้วอยากได้แค่ชื่อ หรือแปลงเป็นข้อความรูปแบบใหม่:

javascript
const users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 },
];

// ดึงเฉพาะชื่อ
const names = users.map(user => user.name);
console.log(names);            // ["Alice", "Bob"]

// แปลงเป็นรูปแบบใหม่
const labels = users.map(user => `${user.name} (${user.age})`);
console.log(labels);           // ["Alice (25)", "Bob (30)"]

4.3 map มี index ให้ด้วย

function ใน map รับ argument ตัวที่ 2 เป็น index:

javascript
const items = ["a", "b", "c"];
const numbered = items.map((item, index) => `${index + 1}. ${item}`);
console.log(numbered);         // ["1. a", "2. b", "3. c"]

Part 5: filter — กรองเอาเฉพาะที่ต้องการ

filter = "เก็บเฉพาะตัวที่ผ่านเงื่อนไข ได้ array ใหม่ที่อาจสั้นกว่าเดิม"

5.1 พื้นฐาน

javascript
const numbers = [1, 2, 3, 4, 5, 6];

const evens = numbers.filter(n => n % 2 === 0);
console.log(evens);            // [2, 4, 6]

อธิบาย: filter รับ function ที่คืน true/false — ถ้า function คืน true สำหรับตัวไหน → เก็บตัวนั้นไว้

text
[1, 2, 3, 4, 5, 6]
 ✗  ✓  ✗  ✓  ✗  ✓     แต่ละตัวผ่าน n => n % 2 === 0
   [2,    4,    6]

5.2 ตัวอย่างใช้จริง

งานจริงที่ใช้ filter บ่อยคือคัดข้อมูลตามหลายเงื่อนไข — เช่นเอาเฉพาะผู้ใช้ที่ active และอายุถึงเกณฑ์:

javascript
const users = [
  { name: "Alice", age: 25, active: true },
  { name: "Bob", age: 17, active: true },
  { name: "Carol", age: 30, active: false },
];

const activeAdults = users.filter(u => u.active && u.age >= 18);
console.log(activeAdults);     // [{ name: "Alice", ... }]

5.3 map กับ filter ต่างกันยังไง — จำให้แม่น

  • map — แปลงทุกตัว → array ใหม่ ยาวเท่าเดิมเสมอ
  • filter — เก็บบางตัว → array ใหม่ อาจสั้นกว่าหรือเท่าเดิม

Part 6: reduce — ยุบ array เป็นค่าเดียว

reduce คือ method ที่ทรงพลังที่สุด — และยากที่สุดสำหรับมือใหม่ — มันใช้ "ยุบ array ทั้งหมดให้เหลือค่าเดียว"

6.1 ตัวอย่างง่ายสุด — หาผลรวม

javascript
const numbers = [1, 2, 3, 4];

const sum = numbers.reduce((total, n) => total + n, 0);
console.log(sum);              // 10

อธิบายทีละขั้น — reduce มี 2 ส่วน:

  1. function (total, n) => total + n — "เอาผลสะสมรวมกับตัวปัจจุบัน"
  2. 0 — ค่าเริ่มต้นของผลสะสม

ลองเดินทีละรอบ:

text
ค่าเริ่มต้น total = 0
รอบ 1: total=0, n=1 → 0 + 1 = 1   → total เป็น 1
รอบ 2: total=1, n=2 → 1 + 2 = 3   → total เป็น 3
รอบ 3: total=3, n=3 → 3 + 3 = 6   → total เป็น 6
รอบ 4: total=6, n=4 → 6 + 4 = 10  → total เป็น 10
ผลลัพธ์: 10

total คือ "ผลสะสม" ที่ส่งต่อจากรอบหนึ่งไปอีกรอบ

💡 เปรียบเทียบ: reduce เหมือน "ก้อนหิมะกลิ้งลงเขา" — มันสะสมขึ้นเรื่อย ๆ จากตัวแรกถึงตัวสุดท้าย

📌 ถ้ายังงง reduce: ลองทำ Lab 1 ก่อน แล้วค่อยกลับมาอ่านอีกรอบ — reduce เป็นเรื่องที่ต้องใช้เวลา ไม่ต้องกังวลถ้ายังไม่เข้าใจทันที

6.2 reduce ทำได้มากกว่าหาผลรวม

reduce ยุบเป็น "อะไรก็ได้" — ไม่จำเป็นต้องเป็นตัวเลข

ยุบเป็น object — นับความถี่:

javascript
const words = ["a", "b", "a", "c", "a", "b"];

const count = words.reduce((acc, word) => {
  acc[word] = (acc[word] ?? 0) + 1;
  return acc;
}, {});                                   // ค่าเริ่มต้นเป็น object ว่าง

console.log(count);            // { a: 3, b: 2, c: 1 }

หาค่ามากสุด:

javascript
const nums = [5, 2, 9, 1, 7];
// ✅ วิธีที่แนะนำ — ใส่ -Infinity เป็นค่าเริ่มต้นเสมอ ปลอดภัยแม้ array ว่าง
const max = nums.reduce((m, n) => n > m ? n : m, -Infinity);
console.log(max);              // 9

💡 ทำไมใช้ -Infinity เป็นค่าเริ่มต้น? — เพราะตัวเลขทุกตัวมากกว่า -Infinity เสมอ ทำให้รอบแรกได้สมาชิกตัวแรกเป็น m โดยอัตโนมัติ และถ้า array ว่าง ก็จะได้ -Infinity กลับมาแทนที่จะ throw Error

💡 ทางเลือกสั้นกว่าสำหรับหาค่าสูงสุด: Math.max(...nums) — แต่จะได้ -Infinity ถ้า array ว่าง ซึ่งถือว่าสมเหตุสมผล

ยุบ array ของ object เป็นยอดรวม:

javascript
const cart = [
  { name: "หนังสือ", price: 200 },
  { name: "ปากกา", price: 30 },
  { name: "สมุด", price: 50 },
];

const total = cart.reduce((sum, item) => sum + item.price, 0);
console.log(total);            // 280

6.3 ⚠️ อย่าลืมค่าเริ่มต้น

javascript
[1, 2, 3].reduce((a, b) => a + b, 0);    // ✅ มีค่าเริ่มต้น 0
[].reduce((a, b) => a + b);              // ❌ Error — array ว่าง + ไม่มีค่าเริ่มต้น
[].reduce((a, b) => a + b, 0);           // ✅ 0

ใส่ค่าเริ่มต้นเสมอ — ปลอดภัยกว่า


Part 7: ต่อ Method เข้าด้วยกัน — Data Pipeline (สายท่อข้อมูล)

📌 data pipeline = "สายท่อข้อมูล" — เอาข้อมูลใส่ปลายทางหนึ่ง แล้วต่อขั้นตอนแปลง/กรอง/รวมเป็นทอด ๆ จนได้ผลลัพธ์ปลายอีกข้าง

พลังจริง ๆ ของ map/filter/reduce คือ — เอามาต่อกันเป็นทอด ๆ

ตัวอย่าง — "หายอดรวมของสินค้าที่ราคาเกิน 50 บาท หลังบวก VAT 7%":

javascript
const products = [
  { name: "A", price: 100 },
  { name: "B", price: 30 },
  { name: "C", price: 80 },
  { name: "D", price: 45 },
];

const total = products
  .filter(p => p.price > 50)        // 1. กรองเอาที่ราคา > 50 → [A(100), C(80)]
  .map(p => p.price * 1.07)          // 2. บวก VAT แต่ละตัว → [107, 85.6]
                                     //    A: 100 * 1.07 = 107 / C: 80 * 1.07 = 85.6
  .reduce((sum, price) => sum + price, 0);  // 3. รวม → 107 + 85.6 = 192.6

console.log(total);            // 192.6

อ่านโค้ดนี้เหมือนอ่านประโยค: "เอา products → กรองที่ราคาเกิน 50 → บวก VAT → รวมทั้งหมด"

นี่คือสไตล์ "functional / declarative" — เราบอก "อยากได้อะไร" ไม่ใช่ "ทำยังไงทีละขั้น" — โค้ดอ่านง่ายกว่า loop ธรรมดามาก

📌 declarative vs imperative: declarative = บอกว่าอยากได้อะไร (เช่น "กรอง > 50 แล้วบวก VAT แล้วรวม") ส่วน imperative = บอกขั้นตอนทำยังไง (เช่น "สร้างตัวแปร total, วน loop, ตรวจเงื่อนไข, บวกเข้า total") — สำนวน map/filter/reduce เป็น declarative ในขณะที่ for/while เป็น imperative

เทียบกับเขียนด้วย loop:

javascript
// แบบ loop — ยาวกว่า อ่านยากกว่า
let total = 0;
for (const p of products) {
  if (p.price > 50) {
    total += p.price * 1.07;
  }
}

Part 8: Array Methods อื่น ๆ ที่ใช้บ่อย

8.1 sort — เรียงลำดับ (ระวังกับดัก!)

javascript
[3, 1, 2].sort();              // [1, 2, 3] — บังเอิญถูก! เพราะตัวเลขหลักเดียวเรียง unicode ตรงกับลำดับตัวเลขพอดี
[10, 2, 1].sort();             // [1, 10, 2] — ⚠️ ผิด!

ทำไม [10, 2, 1] เรียงผิด? — เพราะ sort แบบไม่ใส่อะไร มันแปลงทุกตัวเป็น string แล้วเรียงตามตัวอักษร — "10" มาก่อน "2" (เพราะ "1" < "2")

→ เรียงตัวเลข ต้องใส่ compare function (= ฟังก์ชันเปรียบเทียบสองค่า ว่าตัวไหนควรมาก่อน):

javascript
[10, 2, 1].sort((a, b) => a - b);      // [1, 2, 10] — น้อยไปมาก
[10, 2, 1].sort((a, b) => b - a);      // [10, 2, 1] — มากไปน้อย

กฎของ compare function: คืนเลขลบ = a มาก่อน, คืนเลขบวก = b มาก่อน

เรียง object:

javascript
users.sort((a, b) => a.age - b.age);          // เรียงตามอายุ
users.sort((a, b) => a.name.localeCompare(b.name));  // เรียงตามชื่อ

⚠️ sort แก้ array เดิม — ถ้าไม่อยากให้เดิมเปลี่ยน ใช้ toSorted (Part 2.2)

8.2 flat — แผ่ array ซ้อน

flat "แผ่" array ที่ซ้อนกันให้แบนลงหนึ่งชั้น (หรือใส่ Infinity เพื่อแผ่ทุกชั้น) — มีประโยชน์เวลารวม array ของ array เข้าด้วยกัน:

javascript
[1, [2, 3], [4, [5]]].flat();          // [1, 2, 3, 4, [5]]
[1, [2, [3, [4]]]].flat(Infinity);      // [1, 2, 3, 4] — แผ่ทุกชั้น

8.3 flatMap — map แล้ว flat

flatMap คือ map แล้วตามด้วย flat หนึ่งชั้นในขั้นตอนเดียว — เหมาะเวลาที่ฟังก์ชัน map คืน array (เช่นแตกประโยคเป็นคำ) แล้วอยากได้ผลลัพธ์แบนเป็น array เดียว:

javascript
const sentences = ["hello world", "foo bar"];
const words = sentences.flatMap(s => s.split(" "));
console.log(words);            // ["hello", "world", "foo", "bar"]

8.4 slice — ตัดเอาบางส่วน (ไม่แก้ของเดิม)

javascript
const arr = [1, 2, 3, 4, 5];
arr.slice(1, 3)        // [2, 3] — เอา index 1 ถึง 3 (ไม่รวม 3)
arr.slice(2)           // [3, 4, 5] — จาก index 2 ถึงท้าย
arr.slice(-2)          // [4, 5] — 2 ตัวท้าย

⚠️ อย่าสับสน slice (ตัด ไม่แก้เดิม) กับ splice (เพิ่ม/ลบ แก้เดิม)

8.5 join — รวม array เป็น string

join รวมสมาชิกทุกตัวของ array เป็นข้อความเดียว โดยคั่นด้วยตัวอักษรที่กำหนด — ตรงข้ามกับ split ของ string:

javascript
["a", "b", "c"].join("-")              // "a-b-c"
["a", "b", "c"].join(", ")             // "a, b, c"

8.6 forEach — วนทำงาน (ทบทวนจากบทที่ 04)

javascript
[1, 2, 3].forEach(n => console.log(n));

forEach ใช้ "ทำอะไรกับแต่ละตัว" (side effect = ผลข้างเคียง เช่นไปแก้ตัวแปรข้างนอก, print, ส่ง HTTP) — ไม่คืนค่า. ถ้าต้องการ array ใหม่ → ใช้ map


Part 9: เทคนิคที่ใช้บ่อยในงานจริง

9.1 ตัดค่าซ้ำ

ตัดค่าซ้ำออกจาก array ด้วยการแปลงผ่าน Set แล้ว spread กลับ — สำนวนสั้นที่สุดและนิยมที่สุด:

javascript
const arr = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(arr)];      // [1, 2, 3] (จำ Set จากบทที่ 06)

9.2 หาผลรวม / ค่าเฉลี่ย

หาผลรวมด้วย reduce (สะสมทีละตัว) แล้วหารด้วยจำนวนสมาชิกเพื่อได้ค่าเฉลี่ย — งานพื้นฐานที่เจอตลอด:

javascript
const scores = [85, 90, 78, 92];
const sum = scores.reduce((a, b) => a + b, 0);
const average = sum / scores.length;

9.3 จัดกลุ่ม (group by)

การจัดกลุ่มข้อมูลตามค่าใดค่าหนึ่ง (เช่นกลุ่มคนตามเมือง) ทำได้ด้วย reduce สะสมเข้า object — หรือใช้ Object.groupBy ตัวใหม่ (ES2024) ที่สั้นกว่า:

javascript
const people = [
  { name: "Alice", city: "Bangkok" },
  { name: "Bob", city: "Tokyo" },
  { name: "Carol", city: "Bangkok" },
];

const byCity = people.reduce((groups, person) => {
  const city = person.city;
  groups[city] = groups[city] ?? [];
  groups[city].push(person);
  return groups;
}, {});
// { Bangkok: [Alice, Carol], Tokyo: [Bob] }

หรือใช้ Object.groupBy (ES2024 — ใหม่):

javascript
const byCity = Object.groupBy(people, person => person.city);
console.log(byCity);
// {
//   Bangkok: [{ name: "Alice", city: "Bangkok" }, { name: "Carol", city: "Bangkok" }],
//   Tokyo:   [{ name: "Bob", city: "Tokyo" }]
// }

📦 Object.groupBy เป็น ES2024 — ต้อง Node.js 21+, Chrome 117+, Firefox 119+, Safari 17.4+ ถ้ารันที่เก่ากว่านี้ ใช้สำนวน reduce ด้านบนแทน

🔭 มองไปข้างหน้า — Iterator helpers (Stage 4, ตรวจสอบสถานะ/เวอร์ชันล่าสุดก่อนใช้): TC39 รับ proposal Iterator.prototype.map/filter/take/... เข้า Stage 4 แล้ว ทำให้ใช้ map/filter กับ iterator ได้ตรง ๆ โดยไม่ต้องสร้าง array กลาง — รองรับใน Node.js 22+/Chrome 122+ ขึ้นไป ส่วนเบราว์เซอร์อื่นให้ตรวจสอบสถานะล่าสุดก่อนใช้จริง (เช่น array.values().filter(...).map(...).toArray()) เหมาะกับ lazy pipeline (= ประมวลผลทีละตัวตามต้องการ ไม่สร้าง array ทั้งก้อนไว้ล่วงหน้า) ที่ข้อมูลเยอะ ๆ

9.4 เช็คว่า array ว่างไหม

เช็คว่า array ว่างหรือมีของด้วยการดู .length — JS ไม่มีเมธอด isEmpty() ในตัว:

javascript
if (arr.length === 0) { ... }          // ว่าง
if (arr.length > 0) { ... }            // มีของ

Part 10: Lab — ลงมือทำ

Lab 1: map / filter / reduce

ฝึกต่อ filter → map → reduce เป็นสายเดียว (method chaining = ต่อ method เป็นทอด ๆ ด้วย . — ผลลัพธ์ของอันก่อนเป็น input ของอันถัดไป) — รูปแบบที่ทรงพลังที่สุดของการจัดการข้อมูลใน JS โจทย์: หายอดรวมเฉพาะออเดอร์ที่สำเร็จ:

javascript
const orders = [
  { id: 1, amount: 250, status: "completed" },
  { id: 2, amount: 100, status: "cancelled" },
  { id: 3, amount: 400, status: "completed" },
  { id: 4, amount: 150, status: "completed" },
];

// ยอดรวมของ order ที่ completed เท่านั้น
const totalCompleted = orders
  .filter(o => o.status === "completed")
  .map(o => o.amount)
  .reduce((sum, amount) => sum + amount, 0);

console.log(totalCompleted);   // 800

Lab 2: หา top N

ฝึกเขียนฟังก์ชันทั่วไปหา "อันดับสูงสุด N ตัว" โดย copy array ก่อน sort (ไม่แก้ของเดิม) แล้ว slice — รวม sort + slice + การไม่ทำลายข้อมูลต้นฉบับ:

javascript
function topN(items, key, n) {
  return [...items]                          // copy ก่อน (ไม่แก้ของเดิม)
    .sort((a, b) => b[key] - a[key])
    .slice(0, n);
}

const students = [
  { name: "A", score: 75 },
  { name: "B", score: 92 },
  { name: "C", score: 88 },
  { name: "D", score: 60 },
];

console.log(topN(students, "score", 2));
// [{ name: "B", score: 92 }, { name: "C", score: 88 }]

Lab 3: นับความถี่ของคำ

ฝึกรวมหลายเทคนิคเป็นสายเดียว — toLowerCasesplitfilterreduce เพื่อนับว่าคำไหนปรากฏกี่ครั้ง:

📝 ตัวอย่างนี้ใช้ regex /\s+/ ซึ่งหมายถึง "ช่องว่าง 1 ตัวขึ้นไป (เว้นวรรค, tab, ขึ้นบรรทัด)" — เพื่อแยกคำ ส่วน regex ละเอียดเรียนกันบทที่ 08 ตรงนี้แค่จำว่า \s+ = ช่องว่าง 1 ตัวขึ้นไป ก็พอ

javascript
function wordCount(text) {
  return text
    .toLowerCase()
    .split(/\s+/)                              // แยกคำด้วย regex (เรียนละเอียดบทที่ 08)
    .filter(word => word.length > 0)
    .reduce((count, word) => {
      count[word] = (count[word] ?? 0) + 1;
      return count;
    }, {});
}

console.log(wordCount("the cat the dog the cat"));
// { the: 3, cat: 2, dog: 1 }

Lab 4: แปลงข้อมูล

javascript
const apiData = [
  { user_id: 1, full_name: "Alice Smith", is_active: true },
  { user_id: 2, full_name: "Bob Jones", is_active: false },
];

const cleaned = apiData
  .filter(u => u.is_active)
  .map(u => ({
    id: u.user_id,
    name: u.full_name,
  }));

console.log(cleaned);          // [{ id: 1, name: "Alice Smith" }]

Part 11: Checkpoint

  1. Array index เริ่มนับจากเลขอะไร?
  2. array.at(-1) ทำอะไร?
  3. Mutating vs non-mutating methods ต่างกันยังไง? ทำไม non-mutating ดีกว่า?
  4. map ต่าง filter ยังไง? (เรื่องความยาวของ array ผลลัพธ์)
  5. reduce ทำงานยังไง? ค่าเริ่มต้นสำคัญยังไง?
  6. find ต่าง filter ยังไง?
  7. some ต่าง every ยังไง?
  8. ทำไม [10, 2, 1].sort() เรียงผิด? แก้ยังไง?
  9. slice ต่าง splice ยังไง?
  10. ตัดค่าซ้ำออกจาก array ทำยังไง?

Part 12: สรุปบทนี้

  • Array = รายการข้อมูล — index เริ่มจาก 0
  • Mutating (push, pop, sort, splice) แก้ของเดิม / non-mutating (map, filter, slice, toSorted) สร้างใหม่ — นิยมแบบไม่แก้ของเดิม
  • map — แปลงทุกตัว → array ยาวเท่าเดิม
  • filter — เก็บที่ผ่านเงื่อนไข → array อาจสั้นกว่า
  • reduce — ยุบเป็นค่าเดียว (ผลรวม, object, อะไรก็ได้) — อย่าลืมค่าเริ่มต้น
  • ต่อ method เข้าด้วยกัน = data pipeline ที่อ่านง่ายกว่า loop
  • sort ต้องใส่ compare function สำหรับตัวเลข
  • [...new Set(arr)] = ตัดค่าซ้ำ

บทต่อไป — String, Regex, และวันเวลา


← บทที่ 06 | สารบัญ | บทที่ 08: Strings + Regex + Date →