F8

FULLSTACK HUB

JavaScript 12 tháng 7, 2026 lúc 10:35
Thuộc bài học:[Buổi 20] - Dat 20: Advanced Objects

Dat 20: Advanced Objects (Ghi Chú)

Buổi 20 chính là "trùm cuối" của hệ thống dữ liệu trong JavaScript. Khác với Buổi 19 chỉ là cái vỏ bọc cấu trúc, Buổi 20 ném cho bạn bộ công cụ để thao túng, khóa chặt và nhân bản các Object đó ở cấp độ sâu nhất (phục vụ trực tiếp cho việc xử lý cấu hình Web, SDK và tracking data).

1. QUYỀN LỰC KIỂM SOÁT (Bảo vệ dữ liệu không bị hacker/script khác ghi đè)

Khi viết cấu hình cho web (ví dụ tỷ lệ giảm giá, phí ship), nếu để Object hớ hênh, một đoạn script lỗi nào đó có thể vô tình sửa mất số liệu. F8 ép bạn học 3 cấp độ khóa:

Cấp độ 1: Object.freeze(obj) — Đóng băng tuyệt đối

  • Cơ học: Biến Object thành một tảng băng. Cấm thêm, cấm xóa, cấm sửa.
  • Ứng dụng (Bài 2 - Yêu cầu 1): Dùng để tạo các Object cấu hình mặc định (Config). Nếu ai cố tình gán đè config.mucPhuPhi = 0.8, máy sẽ âm thầm bỏ qua (silently fail) hoặc chửi thẳng mặt báo lỗi (ở strict mode). Kiểm tra bằng Object.isFrozen(obj).

Cấp độ 2: Object.seal(obj) — Niêm phong

  • Cơ học: Đóng kín cái hộp. Cấm nhét thêm đồ mới vào, cấm vứt đồ cũ đi. NHƯNG ĐƯỢC PHÉP sửa giá trị của đồ đã có sẵn.
  • Ứng dụng (Bài 1 - Yêu cầu 8): Khi bạn có 1 Object nhân viên, không cho phép thêm thuộc tính nguoiYeu, nhưng cho phép cập nhật luong. Kiểm tra bằng Object.isSealed(obj).

Cấp độ 3: Object.defineProperty() — Kiểm soát từng cọng lông

  • Cơ học: Can thiệp vào cấp độ DNA (Descriptor) của một cái nhãn (key) bất kỳ. Mỗi cái nhãn đều ẩn chứa 3 công tắc ngầm:

    • writable: Có cho sửa giá trị không? (true/false)

    • enumerable: Có cho phép vòng lặp for...in hoặc Object.keys() nhìn thấy nó không? (true/false)

    • configurable: Có cho phép xóa (delete) cái nhãn này không? (true/false)

  • Ứng dụng (Bài 2 - Yêu cầu 4): Tạo ra một cái id định danh ẩn danh. Gán enumerable: false để khi Hacker dùng vòng lặp quét Object của bạn, cái id đó sẽ tàng hình. Gán writable: false để không ai hack đổi id được.



2. CỖ MÁY NHÀO NẶN DỮ LIỆU (Data Transformation)

Đây là mớ vũ khí giúp bạn sống sót khi làm việc với các mảng dữ liệu (Array of Objects) khổng lồ đổ về từ API.

  • Object.assign(target, source1, source2) — Sáp nhập:

    • Cơ học: Gom tất cả thuộc tính của source đắp vào target. Thằng nào đi sau sẽ đè lên thằng đi trước nếu trùng tên.

    • Ứng dụng (Bài 2 - Yêu cầu 5): Mẹo tạo bản sao không làm chết gốc (Shallow copy): const merged = Object.assign({}, objA, objB). Tạo ra cái hộp {} mới tinh rồi mới đắp đồ vào.

  • Object.groupBy(iterable, callback) — Chia lô phân loại:
    • Cơ học: Ném cho nó 1 mảng các Object. Nó tự động tạo ra các thư mục con dựa trên điều kiện bạn chỉ định.
    • Ứng dụng (Bài 1 - Yêu cầu 9): Phân nhóm 1000 người dùng theo từng phòng ban chỉ bằng 1 dòng code. Trả về: { IT: [...], Marketing: [...] }.
  • Object.fromEntries() — Lật ngược thế cờ:
    • Cơ học: Biến 1 mảng chứa các mảng con [[key, value], [key, value]] thành một Object hoàn chỉnh.
    • Ứng dụng (Bài 1 - Yêu cầu 10): Dùng để dựng "Từ điển tra cứu nhanh". Thay vì phải dùng .find() quét cả mảng để tìm mã số, bạn ép nó thành Object rồi tra bằng obj["A002"] tốc độ chạy dưới RAM nhanh gấp ngàn lần.

3. GETTER VÀ SETTER (Kẻ Gác Cổng)

Không phải thuộc tính nào cũng có sẵn. Đôi khi nó phải tự tính toán lúc được gọi ra.

  • get (Getter): Đóng giả làm một thuộc tính, nhưng thực chất bên trong là một hàm ngầm chạy tính toán.

    • Ứng dụng (Bài 2 - Yêu cầu 2): Gọi instance.total, máy sẽ tự động kích hoạt hàm get total() để cộng dồn giá tiền của các món đồ, thay vì phải gọi hàm instance.getTotal().

  • set (Setter): Trạm kiểm duyệt dữ liệu đầu vào.
    • Ứng dụng: set discountPercent(value). Khi ai đó gán instance.discountPercent = 150, setter sẽ nhảy ra chặn họng kiểm tra if (value > 100) throw new Error("Lỗi!"). Nếu hợp lệ nó mới cho ghi vào RAM.


4. GỠ RỐI TỪ KHÓA this (Bind, Call, Apply)

Đây là nguyên nhân gây ra 90% các vụ tai nạn "Sập Tracking" khi gắn JavaScript vào WordPress.

  • Căn bệnh "Mất trí nhớ": Khi bạn đem một phương thức của Object (VD: instance.print()) ném vào làm Callback cho setTimeout hoặc addEventListener (click chuột), thì từ khóa this bên trong nó sẽ bị bứng khỏi gốc, trỏ thẳng ra ngoài khoảng không window hoặc undefined ➔ Lỗi tung toé (Bài 2 - Yêu cầu 3).

  • Thuốc giải 1: .bind(obj) (Trói buộc vĩnh viễn):
    • Cơ học: Sinh ra một bản sao mới của cái hàm đó, nhưng lấy cái dây thừng trói chặt từ khóa this vào cái obj chỉ định.
    • Code: setTimeout( instance.print.bind(instance), 100 ).
  • Thuốc giải 2: .call(obj, arg1, arg2).apply(obj, [args]) (Mượn xác hoàn hồn):
    • Bắt hàm chạy ngay lập tức, ép this trỏ vào cái xác mình muốn. call truyền tham số rời rạc, apply ném tham số nguyên 1 mảng.


5. PROTOTYPE (CHUỖI DI TRUYỀN)

Đây là cách JavaScript thiết kế sự Kế thừa. Nó không copy dữ liệu, nó tạo ra một sợi dây vô hình (Prototype Chain) liên kết các Object với nhau để tiết kiệm RAM.

  • Khởi tạo kế thừa: Object.create(protoObj) tạo ra một Object mới rỗng tuếch, nhưng có sợi dây nối thẳng vào protoObj (Bài 1 - Yêu cầu 2).

  • Cơ chế dò tìm: Khi bạn gọi item1.introduce().

    1. Máy lục tìm chữ introduce trong người item1. Không có!
    2. Máy lần theo dây truyền máu lên Object Cha (Prototype). Thấy chữ introduce ở đó ➔ Mượn xài luôn.
  • Định vị DNA:
    • Object.getPrototypeOf(obj): Tìm xem bố ruột của cái Object này là ai.
    • Object.hasOwn(obj, "name") hoặc obj.hasOwnProperty("name"): Máy sẽ kiểm tra xem cái thuộc tính "name" này là đồ chính chủ tự có, hay là đồ đi mượn của thằng Cha (Prototype). Trả về true/false (Bài 1 - Yêu cầu 4).


Mớ kiến thức này là xương sống để bạn đâm thẳng vào Bài tập buổi 20 trên F8. Ghi chép xong xuôi vào Hub đi, bạn muốn chúng ta bẻ gãy logic tự luận của Bài 1 (Chứng minh chuỗi di truyền Prototype) trước, hay muốn nhào nặn Bài 2 (Xây Class giỏ hàng kết hợp Setter kiểm duyệt giảm giá) trước?

Thống Kê Liên Kết

Nội bộ
0
Liên kết ngoài
0