
Khi đã nắm vững kiến thức cơ bản, bạn cần học các kiến thức nâng cao sau đây để xây dựng ứng dụng hiện đại, có cấu trúc tốt, hiệu suất cao, dễ bảo trì và đáp ứng các yêu cầu phức tạp hơn.
1. Hàm nâng cao trong JavaScript
Lý thuyết:
- Hàm dưới dạng biểu thức (Function Expressions): là cách khai báo hàm bằng cách gán hàm vào một biến, hằng số, hoặc thuộc tính.
- Arrow Function: Là hàm với cú pháp ngắn gọn, không có
this
riêng. Thích hợp cho callback, hàm nhỏ, không cần dùngthis
. - Callback: là một hàm được truyền như một đối số cho một hàm khác, và sẽ được gọi lại (callback) sau khi hàm kia hoàn thành nhiệm vụ của nó.
Khi dùng:
- Viết các hàm tái sử dụng nhiều lần..
- Xây dựng module tự đóng gói.
- Viết code functional, chia nhỏ xử lý.
Ví dụ:
const greet = (name) => `Hello ${name}`;
function doSomething(cb) {
cb("An");
}
doSomething((name) => console.log("Xin chào " + name));
function counter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const c = counter();
c(); c();
2. Scope và Hoisting nâng cao
Lý thuyết:
- Lexical Scope: là cách JavaScript xác định phạm vi của biến dựa trên vị trí khai báo trong mã nguồn (khi viết mã), chứ không phải dựa trên vị trí gọi hàm khi chương trình chạy.
- Hoisting: là cơ chế mà JavaScript “kéo” các khai báo biến và hàm lên đầu phạm vi (scope) của chúng trước khi code được thực thi.
Khi dùng:
- Biết tránh các lỗi phổ biến khi sử dụng
var
vàthis
. - Viết code an toàn, rõ ràng hơn.
Ví dụ:
console.log(x); // undefined
var x = 5;
function outer() {
const y = 10;
function inner() {
console.log(y);
}
inner();
}
outer();
3. Promise, Async/Await và xử lý bất đồng bộ
Lý thuyết:
- Promise: là một đối tượng đại diện cho kết quả của một tác vụ bất đồng bộ (async), có thể thành công hoặc thất bại trong tương lai.
- Async/Await: là cú pháp hiện đại và ngắn gọn hơn để làm việc với Promise, giúp code bất đồng bộ trông giống code đồng bộ, dễ đọc, dễ bảo trì.
- try…catch: là cú pháp được sử dụng để bắt và xử lý lỗi trong JavaScript, giúp chương trình không bị dừng đột ngột khi có lỗi xảy ra.
Khi dùng:
- Gọi API, fetch dữ liệu.
- Xử lý các tác vụ thời gian dài (file, mạng…).
- Quản lý nhiều bước bất đồng bộ có điều kiện.
Ví dụ đầy đủ: Thay thế Promise chaining bằng async/await
Promise chaining:
codefunction fetchData() {
return new Promise(resolve => {
setTimeout(() => resolve('Dữ liệu từ server'), 1000);
});
}
fetchData()
.then(data => {
console.log(data);
return 'Xử lý tiếp';
})
.then(result => console.log(result))
.catch(err => console.error(err));
Dùng async/await:
codefunction fetchData() {
return new Promise(resolve => {
setTimeout(() => resolve('Dữ liệu từ server'), 1000);
});
}
async function processData() {
try {
const data = await fetchData();
console.log(data);
console.log('Xử lý tiếp');
} catch (error) {
console.error(error);
}
}
processData();
4. DOM Manipulation nâng cao và Event Delegation
Lý thuyết:
- DOM Manipulation nâng cao: Thao tác tạo, sửa, xóa DOM động.
- Event Delegation: Dùng để gán sự kiện cho cha thay vì từng phần tử con. Giúp tối ưu hiệu năng, giảm code.
Khi dùng:
- Quản lý các phần tử DOM.
- Quản lý sự kiện nhiều phần tử một cách tối ưu.
Ví dụ:
document.getElementById("list").addEventListener("click", function(e) {
if (e.target.tagName === "LI") {
console.log(e.target.innerText);
}
});
5. ES6+ và các tính năng hiện đại
Lý thuyết:
- Destructuring, Spread, Rest: Giúp xử lý giá trị từ object hoặc array một cách ngắn gọn.
// Array destructuring
const [a, b] = [1, 2];
console.log(a, b); // 1 2
//Spread Operator (...)
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4]; // [1, 2, 3, 4]
// Rest Operator (...)
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3)); // 6
const [x, ...others] = [1, 2, 3, 4];
console.log(x); // 1
console.log(others); // [2, 3, 4]
- Template Literals: Giúp viết chuỗi dễ dàng với dấu backtick (
`
), hỗ trợ biến và xuống dòng tự nhiên.
const name = 'Bob';
const greeting = `Hello, ${name}!
Chào mừng đến với ES6.`;
console.log(greeting);
- Optional Chaining (?.): Truy cập an toàn vào thuộc tính sâu mà không gây lỗi nếu một phần là
undefined
hoặcnull
.
const user = { profile: { name: 'Alice' } };
console.log(user.profile?.name); // Alice
console.log(user.address?.city); // undefined (không lỗi)
- Nullish Coalescing (??): Trả về vế phải chỉ khi vế trái là
null
hoặcundefined
(khác với||
, không bị ảnh hưởng bởi0
,''
,false
).
const name = null;
const result = name ?? 'Mặc định';
console.log(result); // Mặc định
console.log(0 || 'Mặc định'); // 'Mặc định' (vì 0 bị coi là falsy)
console.log(0 ?? 'Mặc định'); // 0 (chỉ null/undefined mới dùng vế phải)
- Dynamic Import: Import module chỉ khi cần, trả về một Promise.
async function loadModule() {
const module = await import('./myModule.js');
module.hello();
}
- Top-level
await
: Dùngawait
trực tiếp ngoài hàm async (chỉ áp dụng trong module ES).
const data = await fetch('https://api.example.com/data').then(res => res.json());
console.log(data);
6. Module hóa JavaScript (ES6 Modules)
Lý thuyết:
- ES6 Modules: Cho phép chia code thành nhiều file riêng biệt, dễ bảo trì, tránh xung đột tên.
Khi dùng:
- Dự án lớn cần chia code rõ ràng.
- Viết thư viện dùng lại nhiều nơi.
- Áp dụng clean code, SOLID.
Ví dụ:
// math.js
export const add = (a, b) => a + b;
// main.js
import { add } from './math.js';
console.log(add(1, 2));
7. OOP (Lập trình hướng đối tượng) trong JavaScript
Lý thuyết:
- Class: Xây dựng blueprint cho object.
- Prototype: là cơ chế cốt lõi trong JavaScript giúp tất cả các object có thể kế thừa từ nhau thông qua chuỗi prototype chain.
Khi dùng:
- Viết ứng dụng có nhiều object cùng loại (User, Product…).
- Tổ chức code có cấu trúc, dễ bảo trì.
- Áp dụng nguyên tắc OOP: đóng gói, kế thừa, đa hình.
Ví dụ:
// Class definition
class Animal {
constructor(name) {
this.name = name;
}
// Method in the class (automatically added to the prototype)
speak() {
console.log(`${this.name} makes a sound.`);
}
}
// Create an instance of Animal
const animal = new Animal('Lion');
animal.speak(); // Lion makes a sound.
// Class Dog extends Animal (class inheritance)
class Dog extends Animal {
constructor(name, breed) {
super(name); // Call the parent class constructor
this.breed = breed;
}
// Overriding the speak method
speak() {
super.speak(); // Call parent speak()
console.log(`${this.name} barks.`);
}
}
// Create an instance of Dog
const dog = new Dog('Buddy', 'Golden Retriever');
dog.speak();
// Buddy makes a sound.
// Buddy barks.
// Adding a new method to the Animal prototype
Animal.prototype.sleep = function() {
console.log(`${this.name} is sleeping.`);
};
animal.sleep(); // Lion is sleeping.
dog.sleep(); // Buddy is sleeping.
8. Xử lý this, bind, call, apply
this
: trong JavaScript là một từ khóa tham chiếu đến ngữ cảnh (context) mà trong đó hàm đang được gọi.
Ví dụ
const person = {
name: 'Alice',
greet: function() {
console.log(`Hello, my name is ${this.name}`);
}
};
person.greet(); // Hello, my name is Alice
bind
,call
,apply
Cả 3 phương thức này đều dùng để thay đổi ngữ cảnh củathis
, tức là ràng buộcthis
tới một đối tượng cụ thể.bind()
trả về một hàm mới vớithis
được cố định và có thể gọi sau. Không thực thi ngay lập tức, mà bạn có thể gọi hàm sau này.
const person = {
name: 'Alice',
greet: function() {
console.log(`Hello, my name is ${this.name}`);
}
};
const greetAlice = person.greet.bind(person); // bind 'this' to 'person'
greetAlice(); // Hello, my name is Alice
call()
cho phép bạn gọi hàm ngay lập tức, vớithis
được ràng buộc vào đối tượng bạn truyền vào. Truyền tham số ngay lập tức sau đối tượngthis
.
const person = {
name: 'Alice'
};
function greet(age) {
console.log(`Hello, my name is ${this.name} and I am ${age} years old`);
}
greet.call(person, 25); // Hello, my name is Alice and I am 25 years old
apply()
giống nhưcall()
, nhưng tham số được truyền vào dưới dạng một mảng thay vì các đối số riêng biệt. Chạy hàm ngay lập tức.
const person = {
name: 'Alice'
};
function greet(age, city) {
console.log(`Hello, my name is ${this.name} and I am ${age} years old. I live in ${city}.`);
}
greet.apply(person, [25, 'New York']);
// Hello, my name is Alice and I am 25 years old. I live in New York.