Guest Adventurer 🥉 Lv.1
🪙 50
🔷 10
← กลับคลังเนื้อหา
Article · programming

JavaScript Sort และ Reverse

JavaScript

เรียนรู้การเรียงลำดับข้อมูลใน JavaScript ด้วย sort(), toSorted() และ reverse() พร้อมเทคนิคเรียงตัวเลข ข้อความ Object และจัดการ Array โดยไม่แก้ไขข้อมูลต้นฉบับโดยไม่ตั้งใจ

EP12: เรียงลำดับข้อมูลด้วย JavaScript

หลังจากเรียนรู้ Array Methods อย่าง `map()`, `filter()` และ `reduce()` ในตอนที่แล้ว ตอนนี้เราจะมาจัดการข้อมูลอีกขั้นหนึ่ง นั่นคือการเรียงลำดับข้อมูล ไม่ว่าจะเป็นคะแนนจากน้อยไปมาก ราคาสินค้าจากแพงไปถูก รายชื่อเรียงตามตัวอักษร หรือรายการธุรกรรมตามวันที่
JavaScript มี Method สำคัญสำหรับงานนี้ ได้แก่ `sort()` สำหรับเรียงลำดับสมาชิก, `reverse()` สำหรับกลับลำดับสมาชิก และ `toSorted()` สำหรับสร้าง Array ใหม่ที่เรียงลำดับแล้วโดยไม่เปลี่ยน Array ต้นฉบับ
เป้าหมายของบทเรียนคุณจะสามารถเรียงตัวเลขและข้อความได้อย่างถูกต้อง เรียง Object ตามคุณสมบัติที่กำหนด เข้าใจผลกระทบของการแก้ไข Array ต้นฉบับ และเลือกใช้วิธีที่เหมาะสมกับข้อมูลจริง

1. เริ่มต้นด้วย sort()

`sort()` ใช้เรียงลำดับสมาชิกใน Array โดยจะเปลี่ยนแปลง Array ต้นฉบับ และคืนค่าอ้างอิงไปยัง Array เดิมที่ถูกเรียงแล้ว หากเรียกโดยไม่ส่งฟังก์ชันเปรียบเทียบ JavaScript จะเรียงสมาชิกตามลำดับของข้อความเป็นหลัก ซึ่งอาจทำให้ตัวเลขเรียงไม่ตรงกับความคาดหวัง
const names = ['มะลิ', 'กานต์', 'อาทิตย์'];

names.sort();
console.log(names);

const values = [100, 20, 3, 45, 9];
values.sort();
console.log(values);
ตัวอย่างแรกเรียงข้อความตามลำดับการเปรียบเทียบของ JavaScript ส่วนตัวอย่างที่สองอาจได้ลำดับอย่าง `[100, 20, 3, 45, 9]` เพราะตัวเลขถูกเปรียบเทียบในลักษณะข้อความ ไม่ใช่ค่าตัวเลขทางคณิตศาสตร์
ข้อผิดพลาดที่พบบ่อยอย่าใช้ `sort()` แบบไม่ส่งฟังก์ชันเปรียบเทียบเมื่อคุณต้องการเรียงตัวเลขตามค่าจริง เพราะผลลัพธ์อาจแตกต่างจากการเรียงจากน้อยไปมากที่คาดไว้

2. เรียงตัวเลขจากน้อยไปมาก

เมื่อต้องการเรียงตัวเลข ให้ส่งฟังก์ชันเปรียบเทียบเข้าไปใน `sort()` โดยใช้ `(a, b) => a - b` ถ้าผลต่างเป็นค่าลบ `a` จะอยู่ก่อน `b` ถ้าเป็นค่าบวก `b` จะอยู่ก่อน `a` และถ้าเป็นศูนย์ ทั้งสองค่าถือว่าเท่ากันในแง่การเรียงลำดับ
const scores = [78, 95, 42, 88, 61, 100];

scores.sort((a, b) => a - b);
console.log('จากน้อยไปมาก:', scores);

const prices = [120, 35, 450, 12, 89];
prices.sort((a, b) => a - b);
console.log('ราคาจากต่ำไปสูง:', prices);
รูปแบบ `(a, b) => a - b` เป็นรูปแบบที่ใช้บ่อยที่สุดสำหรับการเรียงตัวเลขจากน้อยไปมาก เพราะผลต่างเป็นค่าลบเมื่อ `a` น้อยกว่า `b` และเป็นค่าบวกเมื่อ `a` มากกว่า `b`

3. เรียงตัวเลขจากมากไปน้อย

หากต้องการเรียงจากมากไปน้อย ให้กลับลำดับการลบเป็น `(a, b) => b - a` วิธีนี้เหมาะกับการเรียงคะแนนสูงสุดไว้ด้านบน การแสดงสินค้าราคาสูงก่อน หรือการจัดอันดับยอดขาย
const scores = [78, 95, 42, 88, 61, 100];

scores.sort((a, b) => b - a);
console.log('จากมากไปน้อย:', scores);

const topThree = scores.slice(0, 3);
console.log('สามอันดับแรก:', topThree);
หลังเรียงคะแนนจากมากไปน้อย การใช้ `slice(0, 3)` จะดึงสามสมาชิกแรกออกมาเป็น Array ใหม่ เหมาะกับการสร้างตารางอันดับโดยไม่จำเป็นต้องวนตรวจสอบทุกคะแนนด้วยตนเอง

4. toSorted() เรียงข้อมูลโดยรักษา Array ต้นฉบับ

`toSorted()` เป็น Method ที่สร้าง Array ใหม่ซึ่งมีสมาชิกเรียงลำดับแล้ว โดยไม่แก้ไขลำดับของ Array ต้นฉบับ เหมาะกับระบบที่ต้องการเก็บข้อมูลเดิมไว้ เช่น หน้ารายการสินค้า หน้ารายงาน และแอปพลิเคชันที่จัดการ State
const originalScores = [78, 95, 42, 88, 61];

const ascendingScores = originalScores.toSorted((a, b) => a - b);
const descendingScores = originalScores.toSorted((a, b) => b - a);

console.log('ข้อมูลเดิม:', originalScores);
console.log('เรียงจากน้อยไปมาก:', ascendingScores);
console.log('เรียงจากมากไปน้อย:', descendingScores);
ตัวแปร `originalScores` ยังคงมีลำดับเดิม ขณะที่ `ascendingScores` และ `descendingScores` เป็น Array ใหม่แยกจากกัน `toSorted()` รองรับใน JavaScript สมัยใหม่ หากสภาพแวดล้อมที่ใช้งานไม่รองรับ สามารถใช้ `[...originalScores].sort((a, b) => a - b)` เพื่อคัดลอก Array ก่อนเรียงได้
แนวทางที่แนะนำหากต้องการเรียงข้อมูลเพื่อแสดงผลโดยไม่แก้ไขข้อมูลต้นฉบับ ให้เลือก `toSorted()` หรือสร้างสำเนาด้วย Spread Syntax แล้วจึงเรียก `sort()`

5. reverse() กลับลำดับสมาชิก

`reverse()` ใช้กลับลำดับสมาชิกใน Array โดยเปลี่ยนแปลง Array ต้นฉบับ ไม่ได้เรียงตามค่าตัวเลขหรือตัวอักษร แต่เพียงนำสมาชิกท้ายสุดมาไว้ด้านหน้า และนำสมาชิกตัวแรกไปไว้ด้านท้าย
const steps = ['เริ่มต้น', 'กำลังทำงาน', 'ตรวจสอบ', 'เสร็จสิ้น'];

steps.reverse();
console.log(steps);

const numbers = [10, 30, 20, 40];
const reversedNumbers = [...numbers].reverse();

console.log('ต้นฉบับ:', numbers);
console.log('กลับลำดับ:', reversedNumbers);
ในตัวอย่าง `steps.reverse()` เปลี่ยน Array `steps` โดยตรง ส่วน ` [...numbers].reverse()` สร้างสำเนาก่อนกลับลำดับ จึงไม่กระทบ Array `numbers` เดิม หากต้องการเรียงจากมากไปน้อยตามค่าตัวเลข ควรใช้ฟังก์ชันเปรียบเทียบกับ `sort()` หรือ `toSorted()` โดยตรงเพื่อสื่อความตั้งใจให้ชัดเจน

6. เรียงข้อความและไม่สนใจตัวพิมพ์เล็กใหญ่

การเรียงข้อความด้วย `sort()` โดยตรงอาจได้รับผลจากลำดับรหัสอักขระ ซึ่งทำให้ตัวพิมพ์ใหญ่และตัวพิมพ์เล็กมีลำดับต่างกัน หากต้องการเปรียบเทียบข้อความให้เหมาะกับภาษาที่ใช้งาน สามารถใช้ `localeCompare()` หรือ `Intl.Collator` ได้
const englishNames = ['mango', 'Apple', 'banana', 'cherry'];

const sortedEnglishNames = englishNames.toSorted((a, b) =>
  a.localeCompare(b, 'en', { sensitivity: 'base' })
);

const thaiNames = ['มะลิ', 'กานต์', 'อาทิตย์', 'ขวัญ'];

const thaiCollator = new Intl.Collator('th');
const sortedThaiNames = thaiNames.toSorted(thaiCollator.compare);

console.log(sortedEnglishNames);
console.log(sortedThaiNames);
ตัวเลือก `sensitivity: 'base'` ช่วยให้การเปรียบเทียบภาษาอังกฤษไม่แยกความแตกต่างบางอย่าง เช่น ตัวพิมพ์เล็กกับตัวพิมพ์ใหญ่ ส่วน `Intl.Collator('th')` ใช้กฎการเปรียบเทียบตามภาษาไทย หากต้องการลำดับที่ตรงกับข้อกำหนดเฉพาะของระบบ ควรทดสอบกับข้อมูลจริงและรูปแบบภาษาที่ผู้ใช้ต้องการ

7. เรียง Array ของ Object ตามราคา

ในงานจริง ข้อมูลมักไม่ได้เป็นตัวเลขเดี่ยว แต่เป็น Object ที่มีหลายคุณสมบัติ เช่น สินค้าแต่ละชิ้นมีชื่อ ราคา และจำนวนคงเหลือ เราสามารถเขียนฟังก์ชันเปรียบเทียบโดยเลือกคุณสมบัติที่ต้องการมาใช้ได้
const products = [
  { id: 1, name: 'สมุด', price: 35, stock: 20 },
  { id: 2, name: 'ปากกา', price: 12, stock: 0 },
  { id: 3, name: 'กระเป๋า', price: 450, stock: 8 },
  { id: 4, name: 'ดินสอ', price: 8, stock: 50 },
  { id: 5, name: 'ขวดน้ำ', price: 120, stock: 5 }
];

const cheapestFirst = products.toSorted((a, b) => a.price - b.price);
const mostExpensiveFirst = products.toSorted((a, b) => b.price - a.price);

console.log('ราคาต่ำไปสูง:', cheapestFirst);
console.log('ราคาสูงไปต่ำ:', mostExpensiveFirst);
ในกรณีนี้ `a.price - b.price` ใช้เปรียบเทียบราคาของสินค้าแต่ละรายการ และ `b.price - a.price` ใช้เรียงกลับทิศทาง เนื่องจาก `toSorted()` ไม่เปลี่ยนลำดับใน `products` เราจึงสามารถสร้างรายการเรียงตามราคาหลายแบบได้จากข้อมูลชุดเดียวกัน

8. เรียงข้อมูลหลายเงื่อนไข

บางระบบต้องเรียงข้อมูลด้วยหลายเงื่อนไข เช่น ให้สินค้าที่มีสต็อกอยู่ก่อน แล้วเรียงตามราคาจากน้อยไปมากภายในกลุ่มเดียวกัน วิธีนี้ทำได้โดยตรวจเงื่อนไขแรกก่อน หากผลเท่ากันจึงใช้เงื่อนไขถัดไป
const sortedProducts = products.toSorted((a, b) => {
  const aOutOfStock = a.stock === 0;
  const bOutOfStock = b.stock === 0;

  if (aOutOfStock !== bOutOfStock) {
    return Number(aOutOfStock) - Number(bOutOfStock);
  }

  return a.price - b.price;
});

console.log(sortedProducts);
เงื่อนไขแรกจะจัดสินค้าที่หมดสต็อกไว้หลังสินค้าที่มีสต็อก ส่วนเงื่อนไขที่สองจะเรียงราคาจากต่ำไปสูงภายในกลุ่มเดียวกัน การแยกเงื่อนไขเป็นขั้นตอนช่วยให้ฟังก์ชันเปรียบเทียบอ่านง่ายและแก้ไขต่อได้สะดวก

9. เรียงวันที่และเวลา

หากข้อมูลวันที่ถูกเก็บเป็น Date Object เราสามารถนำค่าเวลาเป็นมิลลิวินาทีมาเปรียบเทียบได้โดยใช้ `getTime()` ส่วนข้อมูลวันที่ที่เป็นข้อความควรแปลงเป็น Date อย่างถูกต้องก่อนเรียง และควรตรวจสอบรูปแบบข้อมูลให้สม่ำเสมอ
const orders = [
  { id: 'A101', createdAt: '2026-10-29T09:30:00Z' },
  { id: 'A102', createdAt: '2026-10-27T14:15:00Z' },
  { id: 'A103', createdAt: '2026-10-28T08:00:00Z' }
];

const oldestFirst = orders.toSorted((a, b) =>
  new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
);

console.log(oldestFirst);
การใช้รูปแบบวันที่มาตรฐานที่มีเขตเวลา เช่น ISO 8601 ช่วยลดความคลุมเครือในการแปลงเวลา ควรหลีกเลี่ยงการนำข้อความวันที่หลายรูปแบบมาเปรียบเทียบโดยตรง และหากข้อมูลมาจากผู้ใช้ ควรตรวจสอบว่าวันที่แปลงได้จริงก่อนนำไปเรียง

10. ความเสถียรของการเรียงลำดับและค่าที่ไม่ใช่ตัวเลข

JavaScript ใช้การเรียงลำดับแบบ Stable Sort ในสภาพแวดล้อมมาตรฐานสมัยใหม่ หมายความว่าสมาชิกที่ถูกเปรียบเทียบว่าเท่ากันจะรักษาลำดับเดิมไว้เมื่อใช้การเรียงตามปกติ อย่างไรก็ตาม ฟังก์ชันเปรียบเทียบควรให้ผลสอดคล้องกัน ไม่เปลี่ยนพฤติกรรมไปมา และไม่ควรคืนค่าที่ผิดชนิดโดยไม่ตั้งใจ
const records = [
  { name: 'A', group: 2 },
  { name: 'B', group: 1 },
  { name: 'C', group: 2 },
  { name: 'D', group: 1 }
];

const sortedRecords = records.toSorted((a, b) => a.group - b.group);
console.log(sortedRecords);

const mixedValues = [10, NaN, 3, 20];
const sortedValues = mixedValues.toSorted((a, b) => {
  if (Number.isNaN(a)) return 1;
  if (Number.isNaN(b)) return -1;
  return a - b;
});

console.log(sortedValues);
ตัวอย่างแรกเรียงตาม `group` โดยสมาชิกที่มีค่า `group` เท่ากันจะคงลำดับสัมพัทธ์เดิมไว้ ส่วนตัวอย่างที่สองแสดงวิธีวาง `NaN` ไว้ท้ายรายการอย่างชัดเจน ทั้งนี้ควรกำหนดกฎการเรียงค่าพิเศษ เช่น `NaN`, `null` หรือค่าที่ขาดหาย ให้ตรงกับความต้องการของระบบ

11. เปรียบเทียบ Method สำหรับเรียงและกลับลำดับ

Methodหน้าที่เปลี่ยน Array ต้นฉบับเหมาะกับงาน
sort(compareFn)เรียงสมาชิกตามกฎที่กำหนดใช่เรียง Array เดิมเมื่อยอมรับการเปลี่ยนแปลงได้
toSorted(compareFn)สร้าง Array ใหม่ที่เรียงแล้วไม่เรียงข้อมูลเพื่อแสดงผลโดยรักษาต้นฉบับ
reverse()กลับลำดับสมาชิกใช่กลับลำดับรายการที่มีอยู่แล้ว
[...array].reverse()คัดลอกแล้วกลับลำดับไม่เปลี่ยน Array เดิมกลับลำดับโดยรักษาข้อมูลต้นฉบับ

12. แบบฝึกหัดท้ายบท

ใช้ข้อมูลต่อไปนี้ฝึกเขียนโค้ดด้วยตนเอง โดยพยายามเลือก Method ที่ตรงกับเป้าหมาย และตรวจสอบด้วยว่า Array ต้นฉบับเปลี่ยนแปลงหรือไม่
const scores = [72, 95, 48, 88, 61, 95];
const students = [
  { name: 'มีนา', score: 82 },
  { name: 'ต้น', score: 95 },
  { name: 'ฟ้า', score: 74 },
  { name: 'นัท', score: 95 }
];

// 1. เรียง scores จากน้อยไปมากโดยไม่แก้ไข Array ต้นฉบับ

// 2. เรียง scores จากมากไปน้อย

// 3. เรียง students ตามคะแนนจากมากไปน้อย

// 4. เรียง students ตามคะแนนจากมากไปน้อย และถ้าคะแนนเท่ากันให้เรียงชื่อตามภาษาไทย

// 5. กลับลำดับ scores โดยไม่แก้ไข Array ต้นฉบับ
เฉลยแบบฝึกหัด
1. `const ascending = scores.toSorted((a, b) => a - b);` เรียงจากน้อยไปมากและรักษา Array ต้นฉบับ 2. `const descending = scores.toSorted((a, b) => b - a);` เรียงจากมากไปน้อย 3. `const sortedStudents = students.toSorted((a, b) => b.score - a.score);` เรียง Object ตามคะแนนจากมากไปน้อย 4. `const thaiCollator = new Intl.Collator('th');` แล้วใช้ `const sortedStudents = students.toSorted((a, b) => b.score - a.score || thaiCollator.compare(a.name, b.name));` หากคะแนนเท่ากันจะใช้ชื่อเป็นเงื่อนไขรอง 5. `const reversedScores = [...scores].reverse();` สร้างสำเนาก่อนกลับลำดับ จึงไม่แก้ไข Array เดิม

13. สรุปและเตรียมพร้อมสำหรับตอนถัดไป

การเรียงลำดับข้อมูลเป็นทักษะสำคัญของ JavaScript โดย `sort()` เหมาะกับการเรียง Array โดยตรงและต้องใช้ฟังก์ชันเปรียบเทียบเมื่อเรียงตัวเลข `toSorted()` ช่วยสร้างผลลัพธ์ใหม่โดยไม่เปลี่ยนลำดับต้นฉบับ ส่วน `reverse()` ใช้กลับลำดับสมาชิก ไม่ใช่การเรียงตามค่าของสมาชิก
ภารกิจหลังเรียนสร้างรายการสินค้าอย่างน้อย 5 รายการ แล้วแสดงผล 3 รูปแบบ ได้แก่ ราคาต่ำไปสูง ราคาสูงไปต่ำ และสินค้าที่มีสต็อกมากไปน้อย โดยใช้ `toSorted()` และตรวจสอบว่า Array ต้นฉบับยังคงเหมือนเดิม
การเรียงข้อมูลที่ถูกต้องเริ่มจากการกำหนดกฎให้ชัดเจน และเลือกวิธีที่รักษาความถูกต้องของข้อมูลเดิม

ตอนถัดไป: **JavaScript Objects และการจัดการข้อมูลเชิงโครงสร้าง** เรียนรู้การเข้าถึงคุณสมบัติ การเพิ่มและลบข้อมูล การคัดลอก Object ด้วย Spread Syntax และการแปลง Object เป็นรูปแบบที่เหมาะกับการใช้งานจริง
อ่านจนถึงระยะ 500px ก่อนท้ายหน้าและอยู่ในหน้านี้อย่างน้อย 5 นาที เพื่อรับ EXP วันละครั้ง

⏳ กำลังจับเวลาอ่าน...

🌐
เลือกภาษา / Select Language
21 World Languages Supported