Danh sách đang hiển thị đủ dữ liệu nhưng sau một lần lấy trang tiếp theo, một số phần tử biến mất khỏi nguồn. Nếu đoạn mã dùng splice để lấy một đoạn mảng, nguyên nhân có thể là thao tác đã thay đổi dữ liệu gốc. Hai tên slice và splice gần giống nhau nhưng phục vụ hai mục đích khác nhau.
1. Phân biệt ba điều trước khi chọn hàm
Theo tài liệu MDN về slice và splice, điểm khác biệt nằm ở tác động lên mảng, ý nghĩa tham số thứ hai và dữ liệu trả về.
| Câu hỏi | slice(start, end) | splice(start, deleteCount, ...items) |
|---|---|---|
| Có sửa mảng gốc? | Không | Có, khi thao tác làm thay đổi phần tử |
| Tham số thứ hai là gì? | Vị trí kết thúc, không lấy phần tử tại vị trí đó | Số phần tử cần xóa |
| Trả về gì? | Mảng mới chứa đoạn được lấy | Mảng chứa phần tử bị xóa |
Không nên thay hàm chỉ vì thấy kết quả trả về trong một ví dụ tình cờ giống nhau. Hãy kiểm tra cả dữ liệu nguồn sau lời gọi.
2. Cùng con số nhưng khác ý nghĩa
const source = ['A', 'B', 'C', 'D', 'E'];
const selected = source.slice(1, 3);
console.log(selected); // ['B', 'C']
console.log(source); // ['A', 'B', 'C', 'D', 'E']
const editable = ['A', 'B', 'C', 'D', 'E'];
const removed = editable.splice(1, 3);
console.log(removed); // ['B', 'C', 'D']
console.log(editable); // ['A', 'E']
Ở lời gọi đầu, số 3 là ranh giới kết thúc. Ở lời gọi sau, số 3 là số lượng cần xóa. Đặt tên biến như selected và removed giúp người đọc nhận ra mục đích thay vì gọi mọi kết quả là data.
3. Lấy một trang dữ liệu mà không cắt mất nguồn
Ví dụ dưới đây dành cho mảng JavaScript thông thường đã được tải đầy đủ vào bộ nhớ. Số trang bắt đầu từ 1; page và pageSize phải là số nguyên an toàn, dương và có độ lớn thực tế phù hợp với ứng dụng.
const allItems = ['A', 'B', 'C', 'D', 'E'];
const page = 2;
const pageSize = 2;
const start = (page - 1) * pageSize;
const visibleItems = allItems.slice(start, start + pageSize);
console.log(visibleItems); // ['C', 'D']
console.log(allItems.length); // 5
Nếu đổi thành splice, danh sách nguồn sẽ bị cắt và lần tính trang tiếp theo có thể dựa trên mảng đã mất phần tử. Phân trang trong bộ nhớ cũng không làm giảm dữ liệu tải từ server: nếu danh sách quá lớn, cần phân trang ở API theo thiết kế riêng.
Không đưa trực tiếp giá trị từ URL vào phép tính mà bỏ qua validation. Quy định rõ cách xử lý trang âm, số thập phân, chuỗi không hợp lệ và trang vượt phạm vi. Đừng để quy tắc chuyển đổi kiểu của JavaScript âm thầm quyết định trải nghiệm người dùng.
4. Splice phù hợp khi muốn thay đổi tại chỗ
const queue = ['draft', 'review', 'publish'];
const removed = queue.splice(1, 1, 'approved');
console.log(queue); // ['draft', 'approved', 'publish']
console.log(removed); // ['review']
Đây là thao tác thay một phần tử có chủ đích. Giá trị trả về không phải queue sau cập nhật. Vì vậy, gán lại queue bằng kết quả splice sẽ làm sai ý định nếu bạn muốn giữ danh sách còn lại.
Trước khi sửa tại chỗ, xác định ai đang giữ tham chiếu đến cùng mảng. Nếu dữ liệu thuộc một component khác, cache dùng chung hoặc state cần cập nhật bất biến, hãy xây dựng mảng kết quả riêng theo quy ước của hệ thống.
5. Slice tạo mảng mới, không sao chép sâu object
const original = [{ title: 'Draft' }];
const copy = original.slice();
copy[0].title = 'Changed';
console.log(original[0].title); // 'Changed'
Mảng ngoài là mới nhưng object bên trong vẫn được dùng chung. Nếu mục tiêu là sửa title độc lập, tạo object thay thế cho phần tử cần sửa, đồng thời xem xét các cấu trúc lồng bên trong. Không coi slice là công cụ sao chép sâu mọi loại dữ liệu.
6. Checklist kiểm thử
- Lấy đoạn giữa: kiểm tra đúng ranh giới và số phần tử.
- Lấy trang cuối thiếu phần tử: kết quả không có phần tử giả.
- Mảng rỗng hoặc trang vượt phạm vi: xử lý theo hợp đồng giao diện.
- Với slice: xác minh mảng nguồn giữ nguyên sau thao tác lấy đoạn.
- Với splice: kiểm tra riêng mảng sau sửa và mảng phần tử bị xóa.
- Với object: kiểm tra việc dùng chung tham chiếu trước khi chỉnh thuộc tính.
Kết luận: Chọn slice khi cần lấy một đoạn mà giữ nguyên cấu trúc mảng nguồn. Chọn splice khi thay đổi tại chỗ là chủ đích, và nhớ rằng kết quả trả về là phần bị xóa, không phải danh sách đã cập nhật.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.