Phần này đúng nghĩa là một mê cung "bẫy rập" cho những ai chỉ học vẹt cú pháp. Nếu bạn không nắm chắc tư duy Tham trị - Tham chiếu đã học ở bài trước, bạn sẽ bị các hàm tìm kiếm này vắt kiệt sức lực vì bug chạy không như ý.
Thế giới 1: Mảng chứa giá trị đơn giản (Tham trị: Số, Chuỗi, Boolean)
1.indexOf() — "Thám tử tìm số nhà"
Mục đích: Tìm xem phần tử nằm ở vị trí (index) số mấy.
Kết quả: Trả về con số cụ thể (
0, 1, 2...). Nếu tìm mỏi mắt không thấy ➔ Trả về-1.
2. includes() — "Bảo vệ check xem có trong danh sách không"
- Mục đích: Chỉ cần biết có hay là không, không quan tâm đứng ở đâu.
Kết quả: Trả về
truehoặcfalse.
const listKeywords = ["seo sun", "giai dau bdsea", "f8 core"];
console.log(listKeywords.indexOf("giai dau bdsea")); // 1 (Nằm ở index 1)
console.log(listKeywords.indexOf("chay ads dạo")); // -1 (Không tìm thấy)
console.log(listKeywords.includes("f8 core")); // true
🔥 Cú lừa NaN kinh điển:
Trong JavaScript, NaN === NaN luôn trả về false (đây là một dị tật của JS). Vì indexOf sử dụng toán tử so sánh nghiêm ngặt (===) dưới bo mạch, nên nó không bao giờ tìm được NaN. Ngược lại, includes ra đời muộn hơn, thuật toán thông minh hơn nên nhận diện được NaN.
const mangQuaiDi = [1, NaN, 3];
console.log(mangQuaiDi.indexOf(NaN)); // -1 (Ủa? Rõ ràng có NaN mà tìm không ra!)
console.log(mangQuaiDi.includes(NaN)); // true (includes xử lý chuẩn xác)Thế giới 2: Mảng chứa các Object phức tạp (Tham chiếu)
Khi mảng của bạn chứa các Object (ví dụ: danh sách trang web, danh sách học viên), bạn CẤM TUYỆT ĐỐI dùng indexOf hay includes. Vì sao? Nhìn cú lừa này:
const users = [{ name: "Bắc" }, { name: "Thiên" }];
console.log(users.includes({ name: "Bắc" })); // false!!!Tại sao lại ra false? Học lại bài 1: Mỗi lần bạn viết { name: "Bắc" } là bạn đang tạo ra một căn nhà mới với địa chỉ mới trong bộ nhớ. Thằng includes đi so sánh địa chỉ của căn nhà trong mảng với căn nhà mới tinh bạn vừa ghi ở ngoài ➔ Hai địa chỉ khác nhau hoàn toàn ➔ Trả về false.
Để xử lý Object, bạn phải dùng bộ đôi có truyền Hàm callback: find() và findIndex().
1. find() — "Thợ săn tìm người"
Cơ chế: Duyệt qua từng Object, chọc vào từng thuộc tính để kiểm tra điều kiện. Thấy thằng nào thỏa mãn phát là bốc nguyên Object đó ra và dừng hàm ngay lập tức (Short-circuiting - Không thèm chạy tiếp các phần tử phía sau để tiết kiệm hiệu năng).
Kết quả: Trả về chính Object đầu tiên tìm thấy. Không thấy ➔
undefined.
2. findIndex() — "Thợ săn tìm vị trí"
- Cơ chế: Y hệt
find(), nhưng thay vì bốc Object, nó chỉ ghi lại số ghế (index) của Object đó. - Kết quả: Trả về index. Không thấy ➔ -1.
const danhSachDuAn = [
{ id: 101, name: "Led Sun", status: "pending" },
{ id: 102, name: "BDSEA Sports", status: "active" },
{ id: 103, name: "Landing Page Test", status: "pending" }
];
// Tìm dự án có id = 102
const duAnCanTim = danhSachDuAn.find(item => item.id === 102);
console.log(duAnCanTim); // { id: 102, name: 'BDSEA Sports', status: 'active' }
// Tìm vị trí của dự án đang "active"
const viTriActive = danhSachDuAn.findIndex(item => item.status === "active");
console.log(viTriActive); // 1
3 Bài Tập Thực Chiến Cứng Tay
Hãy vận dụng toàn bộ tư duy để giải quyết bài toán quản lý dữ liệu thực tế dưới đây.
const heThongWeb = [
{ targetUrl: "/trang-chu", hooks: 45, secure: true },
{ targetUrl: "/dich-vu", hooks: 12, secure: false },
{ targetUrl: "/lien-he", hooks: 0, secure: true }
];
const danhSachDen = ["/hack-web", "/spam-link", "/loi-he-thong"];
Bài 1: Chặn đứng mã độc (Dùng thế giới 1)
"/spam-link". Hãy viết một câu lệnh kiểm tra xem URL này có nằm trong danhSachDen hay không.Nếu có, in ra "CẢNH BÁO: Chặn truy cập!". Nếu không, in ra "An toàn".
Bài 2: Tìm lỗ hổng bảo mật (Dùng thế giới 2)
Khách hàng yêu cầu bạn tìm ra trang web đầu tiên không an toàn (secure: false) để họ tiến hành cài đặt SSL.
- Yêu cầu: Hãy tìm Object của trang web đó.
- Nâng cao: Sau khi dùng hàm tìm được Object đó rồi, nếu bạn sửa thuộc tính
securecủa Object tìm được thànhtrue, thì mảng gốcheThongWebcó bị đổi theo không? Vì sao?
Bài 3: Vá lỗi hệ thống (Kết hợp nâng cao)
Hệ thống cần bảo trì trang /lien-he.
Yêu cầu: Hãy dùng hàm phù hợp để tìm ra vị trí (index) của trang
/lien-hetrong mảngheThongWeb. Sau đó, dùng chính hàm cắt gọt mảng đã học ở bài trước (splicehoặctoSpliced) để thay thế Object tại vị trí đó thành một Object mới hoàn toàn:{ targetUrl: "/lien-he", hooks: 10, secure: true }(tức là đã cập nhật hooks từ 0 lên 10).