Series 3 — JavaScript Fundamentals
JavaScript → DOM → Async → API
Bài 1. JavaScript & DOM – Từ ngôn ngữ lập trình đến tương tác với giao diện Web
1. JavaScript là gì?
Trong quá trình xây dựng website, HTML được sử dụng để tạo cấu trúc nội dung, CSS đảm nhiệm việc trình bày giao diện, còn JavaScript giúp website xử lý logic và phản hồi thao tác của người dùng.
Ví dụ, với một nút bấm đăng ký, HTML tạo ra nút bấm, CSS định dạng màu sắc và kích thước, còn JavaScript có thể xử lý sự kiện khi người dùng nhấn nút, kiểm tra dữ liệu và hiển thị thông báo.
JavaScript là ngôn ngữ lập trình cho phép xây dựng logic và hành vi tương tác cho website. Ngoài trình duyệt, JavaScript còn có thể chạy ở môi trường server thông qua các runtime như Node.js.
Khi JavaScript chạy trên trình duyệt, trình duyệt sử dụng JavaScript Engine để phân tích và thực thi mã nguồn. JavaScript cũng có thể sử dụng những Web API do môi trường trình duyệt cung cấp, chẳng hạn như DOM API, Timer API và Fetch API.
Cần phân biệt JavaScript với DOM: JavaScript là ngôn ngữ lập trình, còn DOM là mô hình biểu diễn tài liệu HTML mà JavaScript có thể truy cập và thay đổi.
2. Những kiến thức nền tảng của JavaScript
2.1. Variables – Biến trong JavaScript
Biến được sử dụng để lưu trữ và tham chiếu đến dữ liệu trong chương trình.
JavaScript có ba từ khóa khai báo biến thường gặp là var, let và const.
let userName = "Khoa";
const age = 21;
var isStudent = true;
let: khai báo biến có thể được gán lại.const: khai báo biến không thể được gán lại sau khi khởi tạo.var: cách khai báo biến cũ, có phạm vi theo hàm hoặc phạm vi toàn cục nếu khai báo ngoài hàm.
Trong JavaScript hiện đại, nên ưu tiên const khi không cần gán lại biến và dùng let khi giá trị cần thay đổi. var vẫn tồn tại trong nhiều đoạn mã cũ nhưng có một số đặc điểm về phạm vi và hoisting dễ gây nhầm lẫn.
Một lưu ý quan trọng: const không làm cho object hoặc array trở thành bất biến. Nó chỉ ngăn việc gán lại biến sang một giá trị khác.
const user = {
name: "Khoa"
};
user.name = "Minh"; // Hợp lệ
// user = {}; // Không hợp lệ
2.2. Data Types – Kiểu dữ liệu
JavaScript có các kiểu dữ liệu nguyên thủy phổ biến:
string: chuỗi ký tự.number: số.boolean: giá trịtruehoặcfalse.undefined: biến đã được khai báo nhưng chưa có giá trị được gán.null: biểu thị sự vắng mặt của giá trị theo chủ đích.bigint: số nguyên lớn.symbol: giá trị định danh duy nhất.
Ngoài ra, JavaScript còn có object, bao gồm object thông thường, array và function.
const name = "Khoa";
const score = 8.5;
const isActive = true;
const skills = ["HTML", "CSS", "JavaScript"];
const user = {
name: "Khoa",
age: 21
};
Hiểu kiểu dữ liệu giúp chúng ta xử lý dữ liệu chính xác hơn, đặc biệt khi lấy dữ liệu từ form, thao tác với array hoặc nhận dữ liệu từ API.
2.3. Operators – Toán tử
Toán tử cho phép thực hiện phép tính, so sánh và kết hợp các điều kiện.
const a = 10;
const b = 5;
console.log(a + b); // 15
console.log(a > b); // true
console.log(a === b); // false
Một điểm cần chú ý là === so sánh cả giá trị lẫn kiểu dữ liệu, trong khi == có thể chuyển đổi kiểu trước khi so sánh.
console.log(5 == "5"); // true
console.log(5 === "5"); // false
Trong đa số trường hợp, nên ưu tiên === và !== để tránh những kết quả khó đoán do ép kiểu ngầm.
2.4. Control Flow – Điều khiển luồng chương trình
Các câu lệnh điều kiện giúp chương trình lựa chọn cách xử lý dựa trên dữ liệu.
const score = 8;
if (score >= 8) {
console.log("Tốt");
} else if (score >= 5) {
console.log("Đạt");
} else {
console.log("Cần cố gắng");
}
Vòng lặp giúp thực hiện một công việc nhiều lần mà không phải viết lại cùng một đoạn mã.
const products = ["Laptop", "Mouse", "Keyboard"];
for (let i = 0; i < products.length; i++) {
console.log(products[i]);
}
Bên cạnh vòng lặp for, JavaScript còn cung cấp while, for...of, for...in và nhiều phương thức xử lý array như forEach().
Việc lựa chọn cấu trúc phù hợp giúp mã nguồn dễ đọc, dễ kiểm tra và giảm lỗi.
2.5. Functions – Hàm trong JavaScript
Hàm giúp đóng gói một nhóm lệnh thành đơn vị có thể tái sử dụng.
function calculateTotal(price, quantity) {
return price * quantity;
}
const total = calculateTotal(100, 3);
console.log(total); // 300
Trong ví dụ này:
pricevàquantitylà tham số.100và3là đối số khi gọi hàm.returntrả kết quả về nơi gọi hàm.
JavaScript cũng hỗ trợ function expression và arrow function:
const calculateTotal = (price, quantity) => {
return price * quantity;
};
Hàm là nền tảng quan trọng để tổ chức logic, xử lý sự kiện và quản lý các thao tác với dữ liệu.
2.6. Arrays & Objects – Tổ chức dữ liệu
Array dùng để lưu trữ một danh sách các giá trị, trong khi object giúp biểu diễn một thực thể với các thuộc tính cụ thể.
const products = [
{ id: 1, name: "Laptop", price: 15000000 },
{ id: 2, name: "Mouse", price: 300000 }
];
Có thể sử dụng map() để chuyển đổi dữ liệu:
const productNames = products.map(product => product.name);
console.log(productNames);
// ["Laptop", "Mouse"]
Hoặc dùng filter() để lọc dữ liệu:
const expensiveProducts = products.filter(
product => product.price > 1000000
);
Các phương thức như map(), filter(), find(), some() và reduce() thường được sử dụng trong các ứng dụng Frontend để xử lý danh sách dữ liệu.
3. Từ JavaScript đến DOM
3.1. DOM là gì?
DOM là viết tắt của Document Object Model. Đây là mô hình biểu diễn tài liệu HTML dưới dạng cấu trúc đối tượng mà JavaScript có thể truy cập và thao tác.
Khi trình duyệt phân tích HTML, nó xây dựng một cấu trúc DOM gồm các node đại diện cho những thành phần trong tài liệu, chẳng hạn như phần tử, văn bản và thuộc tính.
Ví dụ, với HTML:
<body>
<h1>Xin chào</h1>
<p>Đây là website của tôi.</p>
</body>
Có thể hình dung cấu trúc DOM như sau:
document
└── html
└── body
├── h1
│ └── "Xin chào"
└── p
└── "Đây là website của tôi."
Đây là sơ đồ khái quát để dễ hình dung, không phải toàn bộ cấu trúc tài liệu HTML thực tế.
Nhờ DOM, JavaScript có thể tìm một phần tử, thay đổi nội dung, cập nhật class CSS, tạo phần tử mới hoặc phản hồi thao tác của người dùng.
3.2. Truy cập phần tử DOM
Để thao tác với một phần tử HTML, trước tiên chúng ta cần tìm phần tử đó.
Giả sử HTML có:
<h1 id="title">Xin chào</h1>
<p class="description">Nội dung ban đầu</p>
JavaScript có thể truy cập các phần tử bằng querySelector():
const title = document.querySelector("#title");
const description = document.querySelector(".description");
querySelector() nhận một CSS selector và trả về phần tử đầu tiên phù hợp. Nếu không tìm thấy, phương thức trả về null.
Ngoài ra, còn có querySelectorAll() để lấy tất cả phần tử phù hợp dưới dạng một NodeList.
Việc hiểu CSS selector từ những bài HTML và CSS trước đó sẽ giúp bạn sử dụng DOM dễ dàng hơn.
3.3. Thay đổi nội dung HTML
Sau khi lấy được phần tử, chúng ta có thể thay đổi nội dung hiển thị.
const title = document.querySelector("#title");
title.textContent = "Chào mừng đến với JavaScript";
textContent thay đổi nội dung văn bản của phần tử.
Trong khi đó, innerHTML cho phép đọc hoặc thiết lập nội dung HTML bên trong phần tử:
const description = document.querySelector(".description");
description.innerHTML = "<strong>Nội dung được in đậm</strong>";
Cần cẩn thận khi đưa dữ liệu do người dùng cung cấp vào innerHTML, vì nội dung không đáng tin cậy có thể tạo ra nguy cơ Cross-Site Scripting (XSS). Nếu chỉ cần hiển thị văn bản, nên ưu tiên textContent.
3.4. Thay đổi CSS bằng JavaScript
JavaScript có thể thay đổi class của phần tử thông qua classList.
<p id="message">Xin chào!</p>
const message = document.querySelector("#message");
message.classList.add("active");
message.classList.remove("hidden");
message.classList.toggle("highlight");
Các phương thức thường dùng:
add(): thêm class.remove(): xóa class.toggle(): thêm class nếu chưa có, hoặc xóa nếu đã có.contains(): kiểm tra phần tử có class hay không.
Thông thường, nên định nghĩa kiểu dáng trong CSS và dùng JavaScript để thay đổi class. Cách này giúp tách biệt logic và giao diện, đồng thời dễ bảo trì hơn việc sửa trực tiếp nhiều thuộc tính CSS bằng JavaScript.
3.5. Tạo và xóa phần tử DOM
JavaScript không chỉ thay đổi những phần tử đã tồn tại mà còn có thể tạo phần tử mới.
const list = document.querySelector("#product-list");
const item = document.createElement("li");
item.textContent = "Laptop";
list.appendChild(item);
Đoạn mã trên tạo một phần tử li, đặt nội dung văn bản và thêm nó vào phần tử có id="product-list".
Để xóa một phần tử, có thể sử dụng:
item.remove();
Những thao tác này hữu ích khi xây dựng danh sách sản phẩm, thông báo, Todo List hoặc nội dung được tạo ra từ dữ liệu.
4. Events – Xử lý sự kiện
4.1. Event là gì?
Event là một sự kiện xảy ra trong trình duyệt, chẳng hạn như người dùng nhấn nút, nhập dữ liệu, gửi form hoặc di chuyển chuột.
JavaScript có thể đăng ký hàm xử lý để phản hồi những sự kiện này.
Ví dụ:
<button id="hello-button">Nhấn vào đây</button>
<p id="result"></p>
const button = document.querySelector("#hello-button");
const result = document.querySelector("#result");
button.addEventListener("click", () => {
result.textContent = "Bạn vừa nhấn nút!";
});
Khi người dùng nhấn nút, sự kiện click xảy ra và hàm callback được thực thi để cập nhật nội dung đoạn văn.
4.2. addEventListener()
addEventListener() là phương thức phổ biến để đăng ký một hàm xử lý sự kiện cho phần tử.
element.addEventListener("eventName", callback);
Trong đó:
element: phần tử cần lắng nghe sự kiện.eventName: tên sự kiện, ví dụclick,input,submit.callback: hàm được thực thi khi sự kiện xảy ra.
Một ưu điểm của addEventListener() là có thể đăng ký nhiều hàm xử lý cho cùng một loại sự kiện trên cùng phần tử.
4.3. Event Object
Hàm callback có thể nhận một đối tượng sự kiện chứa thông tin về sự kiện vừa xảy ra.
button.addEventListener("click", (event) => {
console.log(event.type);
console.log(event.target);
});
Một số thuộc tính quan trọng:
event.type: loại sự kiện.event.target: phần tử nơi sự kiện bắt đầu.event.currentTarget: phần tử đang được gắn hàm xử lý sự kiện.
Phân biệt target và currentTarget đặc biệt hữu ích khi làm việc với các phần tử lồng nhau hoặc event delegation.
4.4. Event Bubbling và Event Delegation
Trong DOM, nhiều sự kiện có cơ chế bubbling: sự kiện bắt đầu từ phần tử phát sinh rồi có thể lan lên các phần tử cha.
Ví dụ, thay vì gắn một event listener cho từng nút xóa trong danh sách sản phẩm, chúng ta có thể gắn một listener cho phần tử cha và xác định nút được nhấn.
Đây là kỹ thuật gọi là event delegation.
const list = document.querySelector("#product-list");
list.addEventListener("click", (event) => {
const button = event.target.closest(".delete-button");
if (!button || !list.contains(button)) {
return;
}
button.closest(".product-item")?.remove();
});
Trong ví dụ này, khi người dùng nhấn một nút có class delete-button, JavaScript tìm phần tử sản phẩm tương ứng và xóa nó.
Event delegation giúp giảm số lượng listener cần đăng ký, đặc biệt hữu ích với danh sách có nhiều phần tử hoặc nội dung được tạo động.
4.5. Xử lý Form
JavaScript có thể lắng nghe sự kiện submit để xử lý dữ liệu biểu mẫu.
<form id="register-form">
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<button type="submit">Đăng ký</button>
</form>
const form = document.querySelector("#register-form");
form.addEventListener("submit", (event) => {
event.preventDefault();
const formData = new FormData(form);
const email = formData.get("email");
console.log(email);
});
preventDefault() ngăn hành vi mặc định của trình duyệt trong sự kiện gửi form, cho phép JavaScript tự xử lý bước tiếp theo.
Tuy nhiên, việc ngăn gửi form không thay thế validation. Với dữ liệu quan trọng, ứng dụng vẫn cần kiểm tra dữ liệu ở phía server.
5. Kết hợp JavaScript và DOM trong thực tế
Hãy xem xét một ví dụ nhỏ: xây dựng chức năng thêm công việc vào Todo List.
<form id="todo-form">
<input id="todo-input" type="text" placeholder="Nhập công việc" required>
<button type="submit">Thêm</button>
</form>
<ul id="todo-list"></ul>
const form = document.querySelector("#todo-form");
const input = document.querySelector("#todo-input");
const list = document.querySelector("#todo-list");
form.addEventListener("submit", (event) => {
event.preventDefault();
const task = input.value.trim();
if (!task) {
return;
}
const item = document.createElement("li");
item.textContent = task;
list.appendChild(item);
input.value = "";
});
Đoạn mã trên kết hợp nhiều kiến thức đã học:
- Truy cập phần tử bằng
querySelector(). - Lắng nghe sự kiện gửi form bằng
addEventListener(). - Ngăn hành vi mặc định bằng
preventDefault(). - Đọc và kiểm tra dữ liệu nhập vào.
- Tạo phần tử bằng
createElement(). - Cập nhật giao diện bằng
appendChild().
Đây là một ví dụ đơn giản về cách JavaScript biến một trang HTML tĩnh thành giao diện có khả năng tương tác.
Trong ứng dụng thực tế, Todo List có thể được mở rộng với chức năng xóa công việc, đánh dấu hoàn thành, lọc danh sách và lưu dữ liệu vào localStorage.
6. Những khái niệm cần tiếp tục tìm hiểu
Sau khi nắm vững các kiến thức trên, bạn có thể tiếp tục đào sâu những khái niệm thường gặp khi làm việc với JavaScript:
- Scope và Closure: hiểu phạm vi biến và cách hàm có thể giữ quyền truy cập đến môi trường bên ngoài.
- Hoisting: hiểu cách khai báo biến và hàm được xử lý trước khi thực thi mã.
- this, call, apply và bind: tìm hiểu cách xác định ngữ cảnh thực thi của hàm.
- Prototype và Class: hiểu cơ chế kế thừa trong JavaScript.
- Array Methods: sử dụng thành thạo
map(),filter(),reduce(),find()và các phương thức liên quan.
Đây là những kiến thức giúp bạn đọc mã nguồn JavaScript tốt hơn, hiểu cách các thư viện hoạt động và chuẩn bị cho việc học React hoặc Next.js.
Kết luận
JavaScript cung cấp logic và khả năng xử lý dữ liệu cho website, trong khi DOM cho phép JavaScript truy cập và cập nhật cấu trúc HTML mà trình duyệt hiển thị. Khi kết hợp với Events, chúng ta có thể tạo ra những giao diện phản hồi trực tiếp với thao tác của người dùng.
Đối với Frontend Developer, điều quan trọng không chỉ là ghi nhớ cú pháp mà còn phải hiểu cách dữ liệu được xử lý, cách phần tử DOM được cập nhật và cách các sự kiện kích hoạt logic chương trình.
Sau khi nắm vững JavaScript và DOM, bước tiếp theo là tìm hiểu Asynchronous JavaScript & API: cách xử lý những tác vụ bất đồng bộ, gửi yêu cầu đến server và hiển thị dữ liệu thực tế từ API lên giao diện website.










Khoá học lập trình game con rắn cho trẻ em




