JavaScript: Khám phá Hệ thống Kiểu Dữ Liệu và Cơ Chế Tĩnh (Scope) Cơ Bản

Thao tác DOM Cơ bản và Chiến lược Tối ưu

DOM (Document Object Model) là giao diện cốt lõi để thao tác với nội dung trang web qua JavaScript. Các phương thức cơ bản cho phép truy cập, sửa đổi và quản lý các phần tử trên trang, tạo nền tảng cho tương tác người dùng động.

Phương thức Chọn Phần tử

Có nhiều cách để chọn phần tử trong DOM, mỗi phương thức có đặc điểm và hiệu năng riêng.

Chọn theo ID: getElementById

Phương thức này là nhanh nhất để truy xuất phần tử theo thuộc tính id.

const targetNode = document.getElementById('main-title');
console.log(targetNode);

Phương thức này hoạt động với độ phức tạp O(1) nhờ sử dụng bảng băm (hash map) bên trong trình duyệt, giúp tìm kiếm nhanh chóng.

Chọn bằng CSS Selector: querySelector và querySelectorAll

Phương thức này cung cấp khả năng chọn phần tử linh hoạt hơn bằng cách sử dụng cú pháp CSS.

// Lấy phần tử đầu tiên khớp với .menu.active
const activeMenu = document.querySelector('.menu.active');

// Lấy tất cả phần tử có class 'item'
const menuItems = document.querySelectorAll('.item');

Phương thức querySelector trả về phần tử đầu tiên khớp, trong khi querySelectorAll trả về tập hợp các phần tử khớp.

Thao tác Nội dung và Cấu trúc

Khi cập nhật nội dung, cần cân nhắc giữa innerHTMLtextContent.

const contentArea = document.getElementById('content');

// Sử dụng innerHTML để chèn HTML
contentArea.innerHTML = '<strong>Chào mừng bạn đến với ứng dụng</strong>';

// Sử dụng textContent để chèn văn bản thuần
contentArea.textContent = '<strong>Chào mừng bạn đến với ứng dụng</strong>';

textContent an toàn hơn vì tự động chuyển đổi các ký tự đặc biệt, phù hợp với dữ liệu người dùng. Trong khi đó, innerHTML có thể gây ra lỗ hổng bảo mật nếu không kiểm soát dữ liệu đầu vào.

Thao tác Đa phần Tử Hiệu quả

Khi cần thêm nhiều phần tử cùng lúc, sử dụng DocumentFragment để tránh các lần reflow không cần thiết.

const fragment = document.createDocumentFragment();
const container = document.getElementById('items-container');

for (let i = 0; i < 50; i++) {
    const newItem = document.createElement('div');
    newItem.className = 'list-item';
    newItem.textContent = `Mục ${i + 1}`;
    fragment.appendChild(newItem);
}

container.appendChild(fragment);

Phương pháp này chỉ gây ra một lần reflow thay vì 50 lần, giúp cải thiện hiệu năng đáng kể.

Quản lý Sự kiện và Thay đổi Phong cách

Quản lý sự kiện và thay đổi phong cách là hai yếu tố quan trọng trong việc xây dựng ứng dụng tương tác.

Mô hình Sự kiện

JavaScript sử dụng mô hình sự kiện với ba giai đoạn: thu thập (capturing), mục tiêu (target), và nổi (bubbling).

const parent = document.getElementById('parent');
const child = document.getElementById('child');

parent.addEventListener('click', () => console.log('Giai đoạn thu thập: parent'), true);
child.addEventListener('click', () => console.log('Giai đoạn mục tiêu: child'), false);
parent.addEventListener('click', () => console.log('Giai đoạn nổi: parent'), false);

Trong ví dụ trên, khi click vào phần tử con, thứ tự log sẽ là: giai đoạn thu thập parent, giai đoạn mục tiêu child, giai đoạn nổi parent.

Ngăn chặn Hành vi Mặc định và Sự kiện Nổi

Đôi khi cần ngăn chặn hành vi mặc định hoặc dừng sự kiện nổi.

document.getElementById('submit-btn').addEventListener('click', (event) => {
    event.preventDefault();
    console.log('Đã ngăn chặn hành vi mặc định');
});

preventDefault() ngăn chặn hành vi mặc định (ví dụ: gửi form), trong khi stopPropagation() ngăn dừng sự kiện nổi lên các phần tử cha.

Quản lý Phong cách với CSS Variables

CSS Variables cho phép thay đổi giao diện ứng dụng một cách linh hoạt và hiệu quả.

:root {
  --primary-color: #3a86ff;
  --background: #ffffff;
}

body {
  background-color: var(--background);
  color: var(--primary-color);
}

// Thay đổi biến qua JavaScript
const root = document.documentElement;
root.style.setProperty('--background', '#f0f0f0');
root.style.setProperty('--primary-color', '#007bff');

Việc thay đổi CSS Variables không gây ra reflow, chỉ ảnh hưởng đến repaint, giúp tối ưu hiệu năng khi thay đổi giao diện.

Phân tích Hệ thống Kiểu Dữ Liệu

JavaScript có bảy kiểu dữ liệu nguyên thủy: undefined, null, boolean, number, string, symbol, và bigint. Hiểu rõ đặc điểm của từng kiểu là chìa khóa để viết mã hiệu quả.

undefined và null

Giữa undefinednull có sự khác biệt quan trọng.

let user;
console.log(user); // undefined

let currentUser = null;
console.log(currentUser); // null

undefined là giá trị mặc định khi biến chưa được gán, trong khi null là giá trị "trống" do lập trình viên gán.

Chuyển đổi Ngầm

JavaScript thực hiện chuyển đổi ngầm khi cần thiết, điều này có thể gây ra những bất ngờ nếu không hiểu rõ.

console.log(5 + "5"); // "55" (số 5 chuyển thành chuỗi)
console.log(5 == "5"); // true (chuyển đổi ngầm)
console.log(5 === "5"); // false (so sánh nghiêm ngặt)

Luôn sử dụng === thay vì == để tránh chuyển đổi ngầm không mong muốn.

Bigint và Số Khác

Để xử lý số nguyên lớn, JavaScript cung cấp kiểu dữ liệu BigInt.

const largeNumber = 9007199254740991n;
const another = BigInt("9007199254740991");
console.log(largeNumber + 1n); // 9007199254740992n

Bigint không tương thích với kiểu số thông thường, cần chuyển đổi khi cần kết hợp với các phép toán thông thường.

Phương thức Mảng và Lập trình Hàm

Các phương thức mảng như map, filter, reduce giúp xử lý tập hợp dữ liệu một cách hiệu quả.

map: Chuyển đổi Mảng

Phương thức map tạo ra mảng mới với các phần tử đã được chuyển đổi.

const numbers = [1, 2, 3];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6]

Phương thức này không thay đổi mảng gốc, tuân thủ nguyên tắc bất biến (immutability).

filter: Lọc Mảng

Phương thức filter trả về mảng mới chỉ chứa các phần tử thỏa mãn điều kiện.

const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 20 }
];

const adults = users.filter(user => user.age >= 18);
console.log(adults); // [Alice, Bob]

Có thể kết hợp nhiều phương thức để xử lý dữ liệu một cách rõ ràng:

const total = users
  .filter(user => user.age >= 18)
  .map(user => user.age)
  .reduce((sum, age) => sum + age, 0);

Thẻ: JavaScript DOM Data Types Array Methods Event Handling

Đăng vào ngày 11 tháng 6 lúc 06:55