JavaScript
Arrays
reverse
เรียนรู้ reverse() — method กลับลำดับ element ใน array แบบเปลี่ยนต้นฉบับ (mutating) ตั้งแต่การใช้งานพื้นฐาน, การ return array เดิม (ไม่ใช่ array ใหม่), การ copy ก่อน reverse ด้วย concat(), edge cases (empty, single element, reverse สองครั้ง), ไปจนถึงการใช้ reverse() ในสถานการณ์จริง เช่น กลับ breadcrumb และแสดงรายการจากล่าสุดไปเก่าสุด ผ่าน Lab 3 ข้อ
`reverse()` คืออะไร — กลับลำดับ element และเปลี่ยนต้นฉบับ
reverse() เป็น method ใน array ใช้กลับลำดับ (reverse the order) ของ element — element แรกกลายเป็นตัวสุดท้าย, element สุดท้ายกลายเป็นตัวแรก สิ่งที่ต้องรู้: • reverse() เป็น mutating method — **เปลี่ยน array ต้นฉบับ** ไม่เหมือน concat() และ join() ที่เราเรียนมาแล้วซึ่งไม่เปลี่ยนต้นฉบับ • reverse() ไม่รับ argument ใด ๆ • reverse() คืนค่า (return) array ที่กลับลำดับแล้ว — เป็น reference ของ array ต้นฉบับ (ไม่ใช่ array ใหม่) • reverse() ทำงานแบบ in-place — element ถูกสลับตำแหน่งกันภายใน array โดยตรง ไม่ต้องสร้าง array ใหม่ เปรียบเทียบกับ method ที่เรียนมาแล้ว: • concat() → return array ใหม่ ไม่เปลี่ยนต้นฉบับ • join() → return string ไม่เปลี่ยนต้นฉบับ • push() / pop() → เปลี่ยนต้นฉบับ • reverse() → เปลี่ยนต้นฉบับ + return array เดิม
const numbers = [1, 2, 3, 4, 5];
// ใช้ reverse() กลับลำดับ
const reversed = numbers.reverse();
console.log(reversed); // [5, 4, 3, 2, 1]
console.log(numbers); // [5, 4, 3, 2, 1] ← ต้นฉบับเปลี่ยนแล้ว! ✓
จากตัวอย่าง: numbers เปลี่ยนจาก [1,2,3,4,5] เป็น [5,4,3,2,1] — reverse() เปลี่ยน array ต้นฉบับโดยตรง จุดสำคัญมาก: ถ้าคุณใช้ reverse() แล้วอยากเก็บ array เดิมไว้ คุณต้อง copy array ก่อน reverse (ใช้ concat() โดยไม่ส่ง argument) — เราจะพูดถึงเรื่องนี้ในหัวข้อถัดไป
reverse() สลับตำแหน่ง element — ตัวหน้าไปหลัง, ตัวหลังไปหน้า — เปลี่ยน array ต้นฉบับโดยตรง
const tasks = ["ตื่นนอน", "แปรงฟัน", "กินข้าว", "ออกไปทำงาน"];
tasks.reverse();
console.log(tasks);
// ["ออกไปทำงาน", "กินข้าว", "แปรงฟัน", "ตื่นนอน"]
const mixed = [true, 42, "hello", null];
mixed.reverse();
console.log(mixed);
// [null, "hello", 42, true]
`reverse()` return array เดิม — ไม่ใช่ array ใหม่
reverse() คืนค่า array ต้นฉบับที่กลับลำดับแล้ว — **ไม่ใช่ array ใหม่** ผลที่ตามมา: • ถ้า assign `const a = b.reverse()` — a และ b จะชี้ไปที่ array เดียวกัน • `original === reversed` → true (เป็น object เดียวกัน) • การเปลี่ยนค่าในตัวแปรใดตัวแปรหนึ่งจะกระทบอีกตัวด้วย วิธีเก็บ array เดิมไว้: copy array ก่อน reverse โดยใช้ concat() โดยไม่ส่ง argument (`arr.concat()`) เพื่อสร้าง shallow copy แล้วค่อย reverse เทียบกับ concat(): • concat() สร้าง array ใหม่เสมอ → `original.concat([])` จะไม่ได้ reference เดิม • reverse() เปลี่ยน array เดิม → ต้อง copy ก่อนถ้าอยากเก็บต้นฉบับ
const letters = ["a", "b", "c"];
// reverse() return array เดิม
const result = letters.reverse();
console.log(result); // ["c", "b", "a"]
console.log(letters); // ["c", "b", "a"] ← เปลี่ยนเหมือนกัน
// เช็กว่าเป็น object เดียวกัน
console.log(letters === result); // true
const original = ["ต้น", "กลาง", "ท้าย"];
// copy ด้วย concat() → reverse() บน copy
const reversed = original.concat().reverse();
console.log(reversed); // ["ท้าย", "กลาง", "ต้น"] ← กลับลำดับแล้ว
console.log(original); // ["ต้น", "กลาง", "ท้าย"] ← ต้นฉบับไม่เปลี่ยน ✓
// ถ้าไม่ copy ก่อน — ต้นฉบับจะเปลี่ยน
const bad = original.reverse();
console.log(original); // ["ท้าย", "กลาง", "ต้น"] ← เสียหาย!
กฎง่าย ๆ: • ถ้าต้องการกลับลำดับแล้วไม่สนใจต้นฉบับ → ใช้ `arr.reverse()` เลย • ถ้าต้องการกลับลำดับโดยเก็บต้นฉบับไว้ → `arr.concat().reverse()` • concat() ที่ไม่มี argument จะ return shallow copy ของ array — เป็นวิธีที่ปลอดภัยที่สุดในสิ่งที่เราเรียนมาแล้ว
`reverse()` กับ array พิเศษ — empty, single element, reverse สองครั้ง
reverse() มีพฤติกรรมกับ array ในกรณีพิเศษที่ควรรู้: • Empty array `[]` → reverse() ได้ array เปล่าเหมือนเดิม — ถูกต้อง ไม่ error • Single element `["a"]` → ได้ array เดิม — เพราะไม่มีอะไรให้สลับ • reverse สองครั้ง = array กลับมาอยู่ในลำดับเดิม — `arr.reverse().reverse()` → array เหมือนก่อน reverse ครั้งแรก พฤติกรรมเหล่านี้ consistent — reverse() ทำงานโดยไม่พังแม้กับ array พิเศษ
// === empty array — ได้ [] เหมือนเดิม
console.log([].reverse()); // []
// === single element — ไม่มีอะไรเปลี่ยน
console.log(["only"].reverse()); // ["only"]
// === reverse สองครั้ง = คืนค่าเดิม
const items = [1, 2, 3, 4, 5];
items.reverse(); // [5, 4, 3, 2, 1]
items.reverse(); // [1, 2, 3, 4, 5] ← กลับมาเหมือนเดิม
console.log(items); // [1, 2, 3, 4, 5]
| กรณี | input | reverse() ผลลัพธ์ | หมายเหตุ |
|---|---|---|---|
| array ปกติ | [1, 2, 3] | [3, 2, 1] | กลับลำดับ — เปลี่ยนต้นฉบับ |
| empty array | [] | [] | ไม่ error — ได้ [] |
| 1 element | ["x"] | ["x"] | ไม่เปลี่ยนเพราะไม่มีอะไรให้สลับ |
| reverse × 2 | [1, 2, 3] | [1, 2, 3] | กลับมาลำดับเดิม |
ใช้ `reverse()` ในสถานการณ์จริง
reverse() ใช้บ่อยในงานที่ต้องการกลับมุมมองข้อมูล — เช่น แสดงรายการจากล่าสุดไปเก่าสุด, กลับเส้นทาง navigation, หรือจัดเรียงข้อมูลใหม่ ตัวอย่างสถานการณ์: • แสดง notification จากใหม่สุดไปเก่าสุด • แสดง chat message ล่าสุดขึ้นบน • กลับ breadcrumb จากตำแหน่งปัจจุบันไป root • จัดการ stack หรือ queue ที่ต้องการกลับทิศทาง
// === แสดง notification จากล่าสุดก่อน
const notifications = [
"มีคนกดไลก์รูปของคุณ",
"คุณได้รับข้อความใหม่",
"อัปเดตระบบเสร็จแล้ว",
];
// กลับลำดับ — สิ่งล่าสุดจะอยู่ข้างหน้า
const recentFirst = notifications.concat().reverse();
console.log("🔔 การแจ้งเตือน (ล่าสุดก่อน):");
console.log(recentFirst.join("\n"));
// อัปเดตระบบเสร็จแล้ว
// คุณได้รับข้อความใหม่
// มีคนกดไลก์รูปของคุณ
// หรือ reverse แบบเปลี่ยนต้นฉบับเลยถ้าไม่ต้องการเก็บลำดับเดิม
notifications.reverse();
console.log(notifications[0]); // "อัปเดตระบบเสร็จแล้ว" ← notification ล่าสุด
// === breadcrumb ปกติ: จาก Home → หน้าปัจจุบัน
const crumbs = ["Home", "Products", "Laptops"];
// แสดงแบบปกติ (root → current)
console.log(crumbs.join(" > "));
// "Home > Products > Laptops"
// กลับลำดับ — แสดงจากหน้าปัจจุบันกลับไป root
const reversed = crumbs.concat().reverse();
console.log(reversed.join(" < "));
// "Laptops < Products < Home"
// === ใช้ reverse() กับข้อมูลที่รับมาแบบ FIFO → ทำให้เป็น LIFO
const tasks = ["รับออเดอร์", "ชำระเงิน", "จัดส่ง"];
tasks.reverse();
console.log("จัดการจากขั้นตอนสุดท้ายก่อน:");
console.log(tasks.join(" → "));
// จัดส่ง → ชำระเงิน → รับออเดอร์
reverse() ทำงานร่วมกับ method อื่นที่เราเรียนมาแล้วได้ดี: • join() หลัง reverse() — แสดงข้อความที่กลับลำดับแล้ว • push() ก่อน reverse() — สร้าง array แล้วกลับลำดับ • includes() + reverse() — เช็กว่าค่าที่ต้องการอยู่ที่ตำแหน่งใดหลังกลับลำดับ • concat().reverse() — copy และกลับลำดับ โดยไม่เปลี่ยนต้นฉบับ
จุดที่มือใหม่มักพลาด
- reverse() เปลี่ยนต้นฉบับ — มือใหม่ที่คุ้นกับ concat() และ join() มักคิดว่า reverse() สร้าง array ใหม่ — แต่จริง ๆ แล้ว reverse() mutate array เดิม — ถ้าต้องการเก็บต้นฉบับต้อง `arr.concat().reverse()`
- reverse() return array เดิม ไม่ใช่ array ใหม่ — `const x = arr.reverse(); console.log(x === arr);` → true — การเปลี่ยน x จะกระทบ arr ด้วย
- ใช้ reverse() โดยไม่ capture return แล้วคิดว่า array ไม่เปลี่ยน — `arr.reverse()` เปลี่ยน arr แล้วและ return arr ที่กลับลำดับ — ถ้าอยากใช้ค่า return ต้อง `const x = arr.reverse()`
- reverse สองครั้งโดยไม่ตั้งใจ — เวลาเรียก reverse() ใน logic ที่ทำงานหลายรอบเช่นใน loop — array เดิมอาจถูกกลับไปกลับมาโดยไม่รู้ตัว — แก้โดย copy ก่อน `arr.concat().reverse()`
- ลืมว่า reverse() กับ empty array ได้ [] — ไม่ใช่ error — `[].reverse()` → `[]` — ปกติดี บางคนกังวลว่ามันจะพังแต่ไม่พัง
- reverse() กับ single element ได้ array เดิม — `["a"].reverse()` → `["a"]` — ลำดับไม่เปลี่ยนเพราะมีแค่ตัวเดียว