Lập trình · 23/10/2026

JavaScript substring và slice: chỉ mục âm và đảo thứ tự cho kết quả khác nhau

Đổi slice thành substring vì tưởng hai hàm tương đương có thể làm ứng dụng lấy sai đoạn chuỗi. Với chỉ mục dương đúng thứ tự, chúng thường cho cùng kết quả. Khác biệt lộ ra khi chỉ mục âm hoặc ranh giới bắt đầu lớn hơn ranh giới kết thúc.

JavaScript substring và slice: chỉ mục âm và đảo thứ tự cho kết quả khác nhau

Đổi slice thành substring vì tưởng hai hàm tương đương có thể làm ứng dụng lấy sai đoạn chuỗi. Với chỉ mục dương đúng thứ tự, chúng thường cho cùng kết quả. Khác biệt lộ ra khi chỉ mục âm hoặc ranh giới bắt đầu lớn hơn ranh giới kết thúc.

1. Chỉ mục âm không có cùng ý nghĩa

const text = 'ABCDE';
console.log(text.slice(-2)); // DE
console.log(text.substring(-2)); // ABCDE
console.log(text.slice(1, -1)); // BCD
console.log(text.substring(1, -1)); // A

slice có thể dùng chỉ mục âm để tính từ cuối chuỗi. substring xem giá trị âm như 0 rồi áp quy tắc ranh giới của nó. Đối chiếu MDN String.slice và MDN substring.

Ví dụ cuối không có nghĩa substring lấy tới ký tự trước cuối. Một thay đổi tên hàm trong parser có thể làm đoạn lấy ra khác hẳn mà không gây exception. Khi review, cần xem miền giá trị của cả hai chỉ mục thay vì chỉ nhìn chuỗi đầu vào.

2. Đảo ranh giới có thể bị sửa ngầm

const text = 'ABCDE';
console.log(JSON.stringify(text.slice(4, 1))); // ""
console.log(JSON.stringify(text.substring(4, 1))); // "BCD"
console.log(text.substring(1, 4)); // BCD

substring hoán đổi hai ranh giới khi cần; slice trong trường hợp này trả chuỗi rỗng. Nếu start và end bị tính nhầm, substring vẫn có thể trả một đoạn trông hợp lý, khiến lỗi khó nhận ra.

Đừng dựa vào kết quả không rỗng để chứng minh khoảng cắt hợp lệ. Với thao tác do người dùng chọn vùng hoặc parser tính vị trí, ứng dụng phải quyết định khoảng đảo chiều là được phép hay là lỗi cần báo.

3. Biểu diễn khoảng nửa mở theo contract rõ ràng

function cutRange(text, start, end) {
  if (typeof text !== 'string') throw new TypeError('text must be a string');
  if (!Number.isInteger(start) || !Number.isInteger(end)) {
    throw new TypeError('indices must be integers');
  }
  if (start < 0 || end < start || end > text.length) {
    throw new RangeError('invalid range');
  }
  return text.slice(start, end);
}
console.log(cutRange('ABCDE', 1, 4)); // BCD
console.log(JSON.stringify(cutRange('ABCDE', 2, 2))); // ""

Helper chọn contract 0 ≤ start ≤ end ≤ text.length, lấy start và không lấy end. Khoảng có hai đầu bằng nhau là khoảng rỗng hợp lệ. Chỉ mục âm, phân số, chuỗi số và khoảng đảo bị từ chối thay vì được diễn giải ngầm.

Đây là một lựa chọn ứng dụng, không phải quy tắc bắt buộc cho mọi hàm xử lý chuỗi. Nếu sản phẩm cho phép chọn vùng ngược, chuẩn hóa vùng theo chính sách đó trước khi gọi helper; đừng vô tình dựa vào hành vi hoán đổi của một phương thức để quyết định trải nghiệm.

4. Xác định đơn vị của chỉ mục trước khi cắt

Các ví dụ dùng ASCII nên mỗi chữ tương ứng một đơn vị chỉ mục. Với chuỗi JavaScript tổng quát, chỉ mục kiểu này dựa trên UTF-16 code unit, không bảo đảm là ranh giới một ký tự người dùng nhìn thấy. Helper kiểm tra khoảng số học, chưa bảo đảm không tách emoji hoặc cụm dấu.

Nếu yêu cầu là lấy N ký tự hiển thị, cần chọn cách phân đoạn phù hợp thay vì chỉ thay substring bằng slice. Nếu vị trí đến từ API, xác nhận API đang đếm byte, code point hay UTF-16; cùng một con số không tự chứng minh hai hệ thống chỉ cùng một đoạn.

5. Test ranh giới trước khi thay phương thức

  • Khoảng bình thường với chỉ mục đầu và cuối.
  • Chỉ mục âm và khoảng đảo thứ tự.
  • Hai ranh giới bằng nhau, chuỗi rỗng và toàn bộ chuỗi.
  • Chuỗi số, phân số, NaN và vị trí vượt độ dài.
  • Văn bản ngoài ASCII nếu sản phẩm có yêu cầu cắt theo ký tự hiển thị.

Sáu khối mã Việt–Anh đã chạy bằng Node.js, kèm kiểm tra các khoảng hợp lệ và đầu vào sai của helper. Chưa tích hợp parser thực tế hoặc thuật toán phân đoạn ký tự hiển thị.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

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