Nút “trước” của một danh sách quay vòng có thể trả undefined nếu dùng trực tiếp (index - 1) % length. Trong JavaScript, % là phép lấy phần dư; kết quả không tự được đưa vào khoảng chỉ mục không âm mà giao diện cần.
1. Phần dư có thể mang dấu âm
const slides = ['A', 'B', 'C'];
console.log(4 % slides.length); // 1
console.log(-1 % slides.length); // -1
console.log(slides[-1 % slides.length]); // undefined
console.log(slides[2]); // C
Theo MDN remainder operator, phần dư mang dấu của số bị chia. Vì thế -1 % 3 là -1. Với mảng thông thường trong ví dụ, truy cập thuộc tính -1 không có nghĩa là lấy phần tử cuối như một số ngôn ngữ khác.
Chọn chính sách trước khi sửa công thức: chỉ mục vượt biên phải quay vòng, bị chặn ở hai đầu hay bị từ chối? Carousel có thể quay vòng, nhưng trang kết quả tìm kiếm thường cần hành vi khác. Không nên biến mọi chỉ mục không hợp lệ thành một phần tử bất kỳ chỉ vì có thể tính phần dư.
2. Kiểm tra cả chia cho 0 và số 0 âm
console.log(Number.isNaN(1 % 0)); // true
console.log(Object.is(-3 % 3, -0)); // true
console.log((-3 % 3) === 0); // true
Với toán hạng Number, mẫu số 0 cho NaN thay vì một chỉ mục hữu ích. Phần dư còn có thể là -0; so sánh === 0 không phân biệt nó với +0. Các trường hợp này khiến việc chỉ thử một chỉ mục dương không đủ để xác minh helper quay vòng.
Danh sách rỗng cần một nhánh giao diện rõ ràng: ẩn điều hướng, hiển thị trạng thái trống hoặc trả lỗi phù hợp. Đừng tính chỉ mục rồi dùng undefined như một tín hiệu lỗi ngầm. Bài này chỉ xử lý Number, không trộn Number và BigInt.
3. Chuẩn hóa chỉ mục sau khi kiểm tra contract
function wrapIndex(index, length) {
if (!Number.isSafeInteger(index) || !Number.isSafeInteger(length)) {
throw new TypeError('index and length must be safe integers');
}
if (length < 1 || length > 1_000_000) {
throw new RangeError('length must be between 1 and 1000000');
}
const remainder = index % length;
if (remainder === 0) return 0;
return remainder < 0 ? remainder + length : remainder;
}
console.log(wrapIndex(-1, 3)); // 2
console.log(wrapIndex(-7, 3)); // 2
console.log(wrapIndex(4, 3)); // 1
console.log(Object.is(wrapIndex(-3, 3), -0)); // false
Helper yêu cầu hai số nguyên an toàn, độ dài từ 1 đến một triệu. Giới hạn trên là lựa chọn minh họa của ứng dụng. Number.isSafeInteger loại chuỗi số, phân số và số ngoài miền nguyên an toàn; helper không tự ép kiểu.
Phần dư âm được cộng thêm độ dài để đưa vào khoảng 0 đến length - 1. Nhánh remainder === 0 trả hẳn +0. Chỉ cộng khi cần giúp diễn đạt rõ chính sách, trong khi các giới hạn đầu vào giữ phép tính trong miền đã chọn.
4. Helper chỉ chuẩn hóa một số, không xác nhận danh sách
Kết quả hợp lệ theo length chưa bảo đảm phần tử thực sự tồn tại. Mảng thưa vẫn có thể thiếu phần tử tại chỉ mục đó. Nếu danh sách thay đổi giữa lúc tính và lúc truy cập, cần tính lại trên cùng dữ liệu hoặc dùng bản chụp phù hợp với luồng ứng dụng.
Nếu index được tính bằng phép cộng lớn trước khi gọi helper, kiểm tra riêng phép cộng đó. Helper không thể phục hồi độ chính xác đã mất trước khi nhận đối số. Tương tự, số đo thập phân và góc quay cần contract riêng, không nên đưa trực tiếp vào helper dành cho chỉ mục nguyên.
5. Checklist cho điều hướng quay vòng
- Đã xác định quay vòng là hành vi đúng của sản phẩm?
- Có nhánh riêng cho danh sách rỗng và chỉ một phần tử?
- Đã thử chỉ mục âm, bội số âm của độ dài và số lớn?
- Có từ chối phân số, chuỗi số, NaN và Infinity?
- Độ dài và phần tử được đọc từ cùng trạng thái danh sách?
Sáu khối mã Việt–Anh đã chạy bằng Node.js. Kiểm tra bổ sung đối chiếu kết quả với phép tính BigInt, kiểm tra miền chỉ mục, số 0 âm và đầu vào sai. Chưa tích hợp carousel trình duyệt thực tế.




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