JavaScript
Arrays
splice
เรียนรู้ splice() — method เพิ่ม/ลบ/แทนที่ element ใน array แบบเปลี่ยนต้นฉบับ (mutating) ตั้งแต่ splice(start) ลบตั้งแต่ start ถึงจบ, splice(start, deleteCount) ลบจำนวนที่ระบุ, splice(start, deleteCount, ...items) ลบของเก่าใส่ของใหม่, splice(start, 0, ...items) แทรกโดยไม่ลบ, index ติดลบ, การใช้ splice() ในสถานการณ์จริง (ลบสินค้าจากตะกร้า), ไปจนถึงเปรียบเทียบ splice() vs slice() — ผ่าน Lab 5 ข้อ (ลบ, แทรก, แทนที่, index ติดลบ, สถานการณ์จริง)
`splice()` คืออะไร — เพิ่ม/ลบ/แทนที่ element โดยเปลี่ยนต้นฉบับ
splice() เป็น method ที่ใช้ **เพิ่ม, ลบ, หรือแทนที่** element ใน array — โดย **เปลี่ยน array ต้นฉบับโดยตรง** (mutating method) สิ่งที่ต้องรู้ก่อน: • splice() จะ **เปลี่ยน array ต้นฉบับ** — element จะถูกตัดออกไปหรือถูกเพิ่มเข้าไปใน array นั้นเลย • splice() จะ **คืนค่า (return) เป็น array ของ element ที่ถูกลบ** — ถ้าไม่มีอะไรถูกลบ จะได้ array เปล่า [] • splice() ไม่ได้สร้าง array ใหม่แบบ slice() — มันแก้ไข array เดิมแล้ว return เฉพาะของที่ตัดออก ลายเซ็น (signature) ของ splice():
// array.splice(start)
// ลบตั้งแต่ start ถึงจบ — 1 argument
// array.splice(start, deleteCount)
// ลบ deleteCount ตัว — 2 arguments
// array.splice(start, deleteCount, item1, item2, ...)
// ลบ deleteCount ตัว แล้วใส่ item1, item2, ... แทน — 3+ argumentsวิธีจำ: `splice = 'ป'ลี่ยนต้นฉบับ` (เปลี่ยน) — ต่างจาก slice = 'ไม่ป'ลี่ยน (copy) splice() เป็น method ในกลุ่ม "mutator" (เปลี่ยนแปลงข้อมูล) — เช่นเดียวกับ push(), pop(), shift(), unshift(), reverse(), sort() ที่เราเรียนมาแล้ว — ต่างจาก slice() ซึ่งอยู่ในกลุ่ม "accessor" (อ่านข้อมูลโดยไม่เปลี่ยนต้นฉบับ)
splice(1, 2) — ลบ 2 element ตั้งแต่ index 1 — array ต้นฉบับสั้นลง และ return เป็น [B, C]
const letters = ["A", "B", "C", "D", "E"];
// index: 0 1 2 3 4
// splice(1, 2) — เริ่มที่ index 1, ลบ 2 ตัว
const removed = letters.splice(1, 2);
console.log(removed); // ["B", "C"] ← element ที่ถูกตัดออก
console.log(letters); // ["A", "D", "E"] ← ต้นฉบับเปลี่ยนแล้ว ✓สังเกต 2 สิ่งจากตัวอย่าง: 1. `removed` มีค่าเป็น `["B", "C"]` — เป็น array ของ element ที่ถูกตัดออก 2. `letters` เหลือแค่ `["A", "D", "E"]` — ต้นฉบับเปลี่ยนแล้ว เพราะ splice() คือ mutating method
`splice(start)` — ลบตั้งแต่ start ถึงจบ array
เมื่อเรียก `arr.splice(start)` โดยไม่ระบุ `deleteCount` — splice() จะลบ element **ทุกตัวตั้งแต่ index start ไปจนถึงตัวสุดท้าย** พฤติกรรมนี้คล้ายกับการ "ตัดหาง" array ออก — เหลือไว้เฉพาะ element ก่อน start ข้อสังเกต: • `splice(0)` → ลบทั้งก้อน → ได้ array เปล่า — return เป็น array ของทุก element • `splice(1)` → เหลือแค่ element ที่ index 0 • `start` เกิน length → ไม่มีอะไรถูกลบ → return []
const fruits = ["แอปเปิ้ล", "กล้วย", "ส้ม", "มะม่วง", "องุ่น"];
// index: 0 1 2 3 4
// === splice(2) — ลบตั้งแต่ index 2 ถึงจบ
const removed = fruits.splice(2);
console.log(removed); // ["ส้ม", "มะม่วง", "องุ่น"] ← 3 ตัวสุดท้ายถูกตัด
console.log(fruits); // ["แอปเปิ้ล", "กล้วย"] ← เหลือแค่ 2 ตัวแรก ✓
// === splice(0) — ลบทั้งก้อน
const nums = [10, 20, 30, 40, 50];
const all = nums.splice(0);
console.log(all); // [10, 20, 30, 40, 50] ← ได้ทุกตัวคืน
console.log(nums); // [] ← เหลือ array เปล่าconst items = ["a", "b", "c"];
// length = 3
// splice(5) — start = 5 > length → ไม่ลบอะไร
const nothing = items.splice(5);
console.log(nothing); // []
console.log(items); // ["a", "b", "c"] — ไม่เปลี่ยน ✓
// splice(5) ไม่ error — แค่ไม่มีอะไรให้ลบจุดสังเกต: splice(start) ใช้เมื่อต้องการ "ตัดหาง" array — เหลือไว้เฉพาะ element ก่อน start — เร็วกว่าการวนลบลบทีละตัวด้วย pop()
`splice(start, deleteCount)` — ระบุจำนวน element ที่ต้องการลบ
ระบุ `deleteCount` เพื่อบอกว่าต้องการลบกี่ element จากตำแหน่ง start กฎ: • `deleteCount` = 0 → ไม่ลบอะไร (ใช้คู่กับ items เพื่อแทรก — จะอธิบายในหัวข้อถัดไป) • `deleteCount` = 1 → ลบแค่ element ที่ตำแหน่ง start • `deleteCount` = 2 → ลบ element ที่ start และตัวถัดไป • `deleteCount` มากกว่าจำนวนที่เหลือ → ลบตั้งแต่ start ถึงจบ (เหมือน splice(start)) นี่คือรูปแบบที่ใช้บ่อยที่สุดของ splice() — "ลบ N ตัวจากตำแหน่ง X"
const colors = ["แดง", "เขียว", "น้ำเงิน", "เหลือง", "ม่วง", "ชมพู"];
// index: 0 1 2 3 4 5
// === splice(2, 1) — ลบ 1 ตัวที่ index 2 ("น้ำเงิน")
const oneRemoved = colors.splice(2, 1);
console.log(oneRemoved); // ["น้ำเงิน"]
console.log(colors); // ["แดง", "เขียว", "เหลือง", "ม่วง", "ชมพู"]
// "น้ำเงิน" หายไป — element ด้านหลังเลื่อนซ้ายมาแทน ✓
// === splice(1, 3) — ลบ 3 ตัวตั้งแต่ index 1
const colors2 = ["แดง", "เขียว", "น้ำเงิน", "เหลือง", "ม่วง", "ชมพู"];
const threeRemoved = colors2.splice(1, 3);
console.log(threeRemoved); // ["เขียว", "น้ำเงิน", "เหลือง"]
console.log(colors2); // ["แดง", "ม่วง", "ชมพู"]const nums = [10, 20, 30, 40, 50];
// length = 5
// splice(2, 10) — deleteCount = 10 แต่เหลือแค่ 3 ตัว → ลบแค่ 3 ตัว
const removed = nums.splice(2, 10);
console.log(removed); // [30, 40, 50] — ได้แค่ที่เหลือ ไม่ error
console.log(nums); // [10, 20]
// splice(0, 0) — deleteCount = 0 → ไม่ลบอะไร
const items = ["a", "b", "c"];
const r = items.splice(0, 0);
console.log(r); // []
console.log(items); // ["a", "b", "c"] — ไม่เปลี่ยนหัวข้อนี้สอนการลบ — ลบ 1 ตัว ลบหลายตัว หรือลบทั้งหมด — แต่ splice() ทำได้มากกว่านั้น: ใส่ของใหม่แทนที่ของเก่าในขั้นตอนเดียว หัวข้อถัดไปจะพาดู
`splice(start, deleteCount, ...items)` — ลบของเก่าแล้วใส่ของใหม่แทน
splice() รับ argument ถัดจาก `deleteCount` เป็น **items** — ค่าหรือ element ที่ต้องการใส่เข้าไป **แทนที่** element ที่ถูกลบ พฤติกรรม: • ลบ `deleteCount` element จากตำแหน่ง `start` • ใส่ items ทั้งหมดเข้าไปที่ตำแหน่ง `start` เดิม — element ที่เหลือจะเลื่อนไปด้านหลัง • return ยังคงเป็น array ของ element ที่ถูกลบ (เหมือนเดิม) นี่คือความสามารถที่ทำให้ splice() ทรงพลัง — "ลบของเก่า ใส่ของใหม่" ในขั้นตอนเดียว
const letters = ["A", "B", "C", "D", "E"];
// index: 0 1 2 3 4
// === splice(1, 2, "X", "Y") — ลบ "B","C" แล้วใส่ "X","Y" แทน
const removed = letters.splice(1, 2, "X", "Y");
console.log(removed); // ["B", "C"] ← element เดิมที่ถูกลบ
console.log(letters); // ["A", "X", "Y", "D", "E"]
// === splice(2, 1, "Z") — ลบ "C" แล้วใส่ "Z" แทน
const items = ["A", "B", "C", "D", "E"];
items.splice(2, 1, "Z");
console.log(items); // ["A", "B", "Z", "D", "E"]
// "C" หาย → "Z" เข้ามาแทนที่ตำแหน่ง index 2 ✓const nums = [10, 20, 30];
// index: 0 1 2
// === ลบ 1 ตัว (20) แต่ใส่ 3 ตัวแทน → array ยาวขึ้น
const removed = nums.splice(1, 1, 21, 22, 23);
console.log(removed); // [20] ← ลบแค่ 1 ตัว
console.log(nums); // [10, 21, 22, 23, 30]
// 21, 22, 23 ถูกใส่แทนที่ตำแหน่ง index 1 — array ยาวขึ้น ✓- จำนวน items ที่ใส่ ไม่จำเป็นต้องเท่ากับ deleteCount — ใส่มากกว่า array จะยาวขึ้น, ใส่น้อยกว่า array จะสั้นลง
- items ถูกใส่ที่ตำแหน่ง start เหมือนกันหมด — เหมือนเอาก้อนใหม่ไปแทรกตรงนั้น
- argument item เป็น optional — จะใส่กี่ตัวก็ได้ — แต่ต้องมีอย่างน้อย 1 ตัวเพื่อให้เกิดการแทนที่ (ไม่งั้นจะเป็นแค่การลบ)
- return ยังเป็น array ของของที่ถูกลบเสมอ — ไม่ใช่ array ใหม่ที่รวมของเก่ากับของใหม่
`splice(start, 0, ...items)` — แทรกโดยไม่ลบอะไรเลย
เมื่อ `deleteCount = 0` — splice() จะ **แทรก** items เข้าไปที่ตำแหน่ง start โดยไม่ลบ element ใด ๆ เลย นี่คือรูปแบบการ "แทรก" element เข้าไปตรงกลาง array — element ที่อยู่ถัดจาก start จะถูกเลื่อนไปด้านหลังโดยอัตโนมัติ ประโยชน์: • แทรกที่ตำแหน่งใดก็ได้ใน array — ไม่ใช่แค่ต้นหรือท้ายเหมือน push() / unshift() • แทรกหลาย element พร้อมกันได้ • return เป็น [] เพราะไม่มีอะไรถูกลบ
const fruits = ["แอปเปิ้ล", "กล้วย", "องุ่น"];
// index: 0 1 2
// === แทรก "ส้ม" ที่ index 1 — ระหว่าง "แอปเปิ้ล" กับ "กล้วย"
fruits.splice(1, 0, "ส้ม");
console.log(fruits); // ["แอปเปิ้ล", "ส้ม", "กล้วย", "องุ่น"]
// === แทรกหลายตัวที่ index 2
fruits.splice(2, 0, "มะม่วง", "ฝรั่ง");
console.log(fruits); // ["แอปเปิ้ล", "ส้ม", "มะม่วง", "ฝรั่ง", "กล้วย", "องุ่น"]
// === แทรกที่ index 0 — เหมือน unshift()
fruits.splice(0, 0, "ทุเรียน");
console.log(fruits); // ["ทุเรียน", "แอปเปิ้ล", "ส้ม", "มะม่วง", "ฝรั่ง", "กล้วย", "องุ่น"]const nums = [10, 20, 30];
// === แทรก 15 ที่ index 1
const removed = nums.splice(1, 0, 15);
console.log(removed); // [] ← ไม่มี element ไหนถูกลบ
console.log(nums); // [10, 15, 20, 30]
// === แทรกที่ index เท่ากับ length → เหมือน push()
const items = ["a", "b"];
items.splice(items.length, 0, "c", "d");
// splice(2, 0, "c", "d") — start = length = 2
console.log(items); // ["a", "b", "c", "d"]สรุป: `splice(start, 0, ...items)` = insert-only mode — แทรกของใหม่ตรงไหนก็ได้โดยไม่ลบของเก่า อีกวิธีจำ: `deleteCount = 0` → ไม่มี delete → มีแต่ insert
`splice()` กับ index ติดลบ — นับจากท้าย array
splice() รองรับ index ติดลบเช่นเดียวกับ slice() — ใช้หลักการเดียวกันคือ `-1` = element สุดท้าย, `-2` = element รองสุดท้าย, ไปเรื่อย ๆ index ติดลบใช้ได้กับ `start` — ทำให้ลบหรือแทรกจากท้าย array ได้สะดวก กฎ: index ติดลบ = `length + index` — แต่ต้องไม่น้อยกว่า 0 (ถ้าติดลบมากไปจะถูกปรับเป็น 0)
const scores = [55, 70, 45, 90, 60, 85, 75];
// index: 0 1 2 3 4 5 6
// index ติดลบ: -7 -6 -5 -4 -3 -2 -1
// === splice(-1, 1) — ลบตัวสุดท้าย (75)
const last = scores.splice(-1, 1);
console.log(last); // [75]
console.log(scores); // [55, 70, 45, 90, 60, 85]
// === splice(-3, 2) — ลบ 2 ตัว ตั้งแต่ index -3
const nums = [10, 20, 30, 40, 50, 60];
// index ติดลบ: -6 -5 -4 -3 -2 -1
const removed = nums.splice(-3, 2);
// -3 = length 6 + (-3) = 3 → index 3 (40)
// ลบ 2 ตัว: 40, 50
console.log(removed); // [40, 50]
console.log(nums); // [10, 20, 30, 60]const tags = ["js", "css"];
// === แทรก "html" ก่อนตัวสุดท้าย — splice(-1, 0, "html")
tags.splice(-1, 0, "html");
console.log(tags); // ["js", "html", "css"]
// -1 = index 1 → แทรกก่อน "css"
// === แทรกที่ตำแหน่งรองสุดท้าย — splice(-2, 0, ...)
const items = ["a", "b", "c", "d"];
items.splice(-2, 0, "X");
console.log(items); // ["a", "b", "X", "c", "d"]
// -2 = index 2 → แทรกก่อน "c"index ติดลบมีประโยชน์เมื่อ: • ต้องการลบ "N ตัวสุดท้าย" — `arr.splice(-N, N)` • ต้องการแทรกก่อนตัวสุดท้าย — `arr.splice(-1, 0, newItem)` • ต้องการลบ "ตัวก่อนสุดท้าย" — `arr.splice(-2, 1)` ข้อสังเกต: `splice(-1, 1)` = ลบตัวสุดท้าย — ได้ผลเหมือน pop() แต่ return เป็น array (ไม่ใช่ค่าเดี่ยว)
ใช้ `splice()` ในสถานการณ์จริง
splice() ใช้บ่อยในงานจริงเมื่อต้องแก้ไข array ในตำแหน่งที่เฉพาะเจาะจง — ลบสิ่งที่ไม่ต้องการ, แก้ไขข้อมูลผิด, หรือแทรกของใหม่ระหว่างทาง สถานการณ์ที่ใช้ splice(): • ลบรายการออกจากตะกร้าสินค้าตาม index • แก้ไขข้อความในรายการ to-do • แทรกขั้นตอนใหม่ระหว่าง workflow • ลบ element ที่ซ้ำหรือไม่ถูกต้อง • จัดการ queue/list แบบมีเงื่อนไข หัวข้อนี้จะพาใช้ splice() ในโจทย์ที่ใกล้เคียงของจริง
// === ลบสินค้าที่ index 2 (ผู้ใช้กดลบรายการที่ 3)
const cart = ["เมาส์", "คีย์บอร์ด", "จอมอนิเตอร์", "สาย USB", "แผ่นรองเมาส์"];
const removedItem = cart.splice(2, 1);
console.log("ลบ:", removedItem[0]); // "จอมอนิเตอร์"
console.log("ตะกร้าหลังลบ:", cart);
// ["เมาส์", "คีย์บอร์ด", "สาย USB", "แผ่นรองเมาส์"]
// === ใช้ splice() กับฟังก์ชันลบตาม index
function removeItem(arr, index) {
if (index >= 0 && index < arr.length) {
return arr.splice(index, 1)[0]; // ลบ 1 ตัว — return ตัวที่ถูกลบ
}
return null;
}
const tasks = ["ซื้อของ", "ออกกำลังกาย", "อ่านหนังสือ", "ตอบอีเมล"];
const done = removeItem(tasks, 1);
console.log("เสร็จ:", done); // "ออกกำลังกาย"
console.log("เหลือ:", tasks); // ["ซื้อของ", "อ่านหนังสือ", "ตอบอีเมล"]// === แก้ไขชื่อสินค้าที่ index 1
const products = ["iPhone 14", "iPhone 15", "iPhone 16"];
// แทนที่ iPhone 15 ด้วย iPhone 15 Pro
products.splice(1, 1, "iPhone 15 Pro");
console.log(products); // ["iPhone 14", "iPhone 15 Pro", "iPhone 16"]
// === แทรกขั้นตอนใหม่ระหว่าง workflow
const steps = ["รับ order", "แพ็คของ", "จัดส่ง"];
// ต้องเพิ่ม "ตรวจสอบคุณภาพ" หลัง "แพ็คของ"
steps.splice(2, 0, "ตรวจสอบคุณภาพ");
console.log(steps);
// ["รับ order", "แพ็คของ", "ตรวจสอบคุณภาพ", "จัดส่ง"]// === ลบ element ด้วยค่า (ไม่รู้ index) — ใช้ indexOf() ช่วยหา
const fruits = ["แอปเปิ้ล", "กล้วย", "ส้ม", "มะม่วง", "กล้วย"];
// อยากลบ "กล้วย" ตัวแรก — หา index ก่อน
const idx = fruits.indexOf("กล้วย"); // idx = 1
if (idx !== -1) {
fruits.splice(idx, 1);
}
console.log(fruits); // ["แอปเปิ้ล", "ส้ม", "มะม่วง", "กล้วย"]
// "กล้วย" ตัวแรก (index 1) ถูกลบ — ตัวที่ 2 ยังอยู่ข้อสังเกตจากตัวอย่าง: • `splice(index, 1)[0]` — ลบ 1 ตัวแล้วดึงค่าที่ถูกลบออกมาใช้ต่อได้ — return ของ splice() เป็น array • `splice(index, 1, newValue)` — แทนที่ 1 element ด้วยค่าใหม่ — ใช้แทนการ assign โดยตรงเมื่ออยากได้ return ด้วย • splice() + indexOf() = "ลบด้วยค่า" — หา index ด้วย indexOf() แล้วลบด้วย splice() — pattern ที่ใช้บ่อย
`splice()` vs `slice()` — เปรียบเทียบเพื่อนที่ชื่อคล้ายกันแต่นิสัยตรงข้าม
splice() กับ slice() เป็นสอง method ที่ชื่อคล้ายกันมาก (ต่างกันแค่ตัว p) — แต่นิสัยตรงข้ามกันโดยสิ้นเชิง — slice() ไม่เปลี่ยนต้นฉบับ, splice() เปลี่ยนต้นฉบับ มือใหม่สับสน 2 ตัวนี้บ่อยมาก — ตารางนี้จะช่วยให้จำได้แม่น:
| เรื่อง | slice() | splice() |
|---|---|---|
| เปลี่ยนต้นฉบับ? | ไม่ — mutating = false | ใช่ — mutating = true |
| return คืออะไร | array ใหม่ที่มี element ที่ดึงออกมา | array ของ element ที่ถูกลบ |
| สร้าง array ใหม่ไหม | ใช่ — return เป็น array ใหม่ | ไม่ — ต้นฉบับถูกเปลี่ยน return เป็นของเก่า |
| ทำอะไรได้บ้าง | ดึงบางส่วนของ array เท่านั้น | ลบ / เพิ่ม / แทนที่ element |
| รับกี่ argument | 2 ตัว: start, end | 3+ ตัว: start, deleteCount, items... |
| end เป็น inclusive? | ไม่ — end ไม่รวม | ไม่มี end — มี deleteCount แทน |
| index ติดลบ | ใช้ได้ทั้ง start และ end | ใช้ได้กับ start |
| ใช้เมื่อไหร่ | ต้องการส่วนย่อยของ array โดยเก็บของเก่าไว้ (view) | ต้องการแก้ไข array โดยตรง — ลบ/เพิ่ม/แทนที่ (modify) |
const original = ["A", "B", "C", "D", "E"];
// === slice(1, 3) — ดึง "B", "C" โดยไม่เปลี่ยนต้นฉบับ
const arr1 = ["A", "B", "C", "D", "E"];
const sliced = arr1.slice(1, 3);
console.log(sliced); // ["B", "C"] ← array ใหม่
console.log(arr1); // ["A","B","C","D","E"] ← ต้นฉบับเหมือนเดิม
// === splice(1, 2) — ลบ "B", "C" — ต้นฉบับเปลี่ยน!
const arr2 = ["A", "B", "C", "D", "E"];
const spliced = arr2.splice(1, 2);
console.log(spliced); // ["B", "C"] ← element ที่ถูกลบ
console.log(arr2); // ["A", "D", "E"] ← ต้นฉบับเปลี่ยนแล้ว!- วิธีจำง่าย ๆ: slice() = **ไม่**เปลี่ยน (copy, view, read) — splice() = **เปลี่ยน** (modify, write, mutate)
- สังเกต: slice() กับ splice() ใส่ argument 1 ตัว (`slice(1)` vs `splice(1)`) — slice(1) ดึงตั้งแต่ index 1 ถึงจบแบบไม่เปลี่ยนต้นฉบับ — splice(1) ลบตั้งแต่ index 1 ถึงจบแบบเปลี่ยนต้นฉบับ
- ถ้าต้องการส่วนหนึ่งของ array ไปใช้ต่อโดยไม่กระทบของเดิม → ใช้ slice() — ถ้าต้องการลบหรือแก้ไข array โดยตรง → ใช้ splice()
- splice() รับ item argument ทำให้ "ลบของเก่าใส่ของใหม่" ได้ — slice() ทำแบบนั้นไม่ได้