JavaScript ES6+ Features Every Developer Should Know - Modern JS Mastery
Master modern JavaScript with ES6+ features including arrow functions, destructuring, template literals, async/await, modules, and more. Level up your coding skills today.
Bạn có bao giờ tự mở một dự án JavaScript hiện đại và thấy những ký hiệu lạ như =>, ..., `${}` khiến bạn bối rối? Đó chính là sức mạnh của ES6+ — bộ tính năng mới đã cách mạng hóa cách chúng ta viết JavaScript.

Nếu bạn vẫn đang viết JavaScript theo phong cách năm 2014 với var, callback lồng nhau và string concatenation, thì bài viết này sẽ đưa bạn lên tầm cao mới. Hãy cùng khám phá những tính năng ES6+ quan trọng nhất mà mọi developer hiện đại đều cần biết.
ES6+ Là Gì?
ES6 (ECMAScript 2015) là phiên bản thứ sáu của tiêu chuẩn ECMAScript — ngôn ngữ nền tảng của JavaScript. Kể từ đó, mỗi năm một phiên bản mới được phát hành (ES2016, ES2017, …, ES2024). Những tính năng này đã được hỗ trợ rộng rãi bởi tất cả các trình duyệt hiện đại và Node.js.
Tại sao ES6+ quan trọng? Nó giúp code của bạn:
- Ngắn gọn hơn — ít dòng code hơn cho cùng một logic
- Dễ đọc hơn — cú pháp rõ ràng, trực quan
- Ít lỗi hơn — các tính năng mới giảm thiểu sai sót phổ biến
- Mạnh mẽ hơn — công cụ xử lý bất đồng bộ tốt hơn
1. Arrow Functions — Hàm Mũi Tên
Arrow functions (=>) là cú pháp ngắn gọn để viết hàm, ra đời từ ES6.
// Trước đây — ES5
const add = function(a, b) {
return a + b;
};
// Bây giờ — ES6+
const add = (a, b) => a + b;
Điểm đặc biệt: khi chỉ có một tham số, bạn có thể bỏ qua dấu ngoặc đơn:
// Cả hai cách đều đúng
const double = (x) => x * 2;
const double = x => x * 2; // Ngắn gọn hơn!
Khi nào KHÔNG dùng arrow function?
Arrow function không có this riêng — nó kế thừa this từ ngữ cảnh bao quanh. Điều này có nghĩa là bạn không nên dùng arrow function làm phương thức của object:
// ❌ Sai — this sẽ là undefined hoặc global
const user = {
name: 'Dev',
greet: () => console.log(`Hello, ${this.name}`)
};
// ✅ Đúng — dùng regular function
const user = {
name: 'Dev',
greet() {
console.log(`Hello, ${this.name}`);
}
};
2. Template Literals — Chuỗi Ktemplate
Template literals sử dụng dấu backtick (`) thay vì dấu nháy đơn hoặc kép, cho phép bạn nhúng biến và biểu thức trực tiếp vào chuỗi.
const name = 'Devs2';
const year = 2026;
// Trước đây — String concatenation phức tạp
const greeting = 'Chào mừng đến với ' + name + '! Năm ' + year;
// Bây giờ — Template literal sạch sẽ
const greeting = `Chào mừng đến với ${name}! Năm ${year}`;
Bạn cũng có thể viết đa dòng mà không cần \n:
const html = `
<div class="card">
<h2>${title}</h2>
<p>${description}</p>
<button>Xem thêm</button>
</div>
`;
Kết hợp với arrow functions, template literals tạo nên sự kết hợp cực kỳ mạnh mẽ:
const users = [
{ name: 'An', age: 25 },
{ name: 'Bình', age: 30 },
{ name: 'Chi', age: 28 }
];
// Tạo danh sách HTML đẹp mắt
const userList = users.map(user =>
`<li>${user.name} — ${user.age} tuổi</li>`
).join('');
3. Destructuring — Giải Cấu Trúc
Destructuring cho phép bạn trích xuất giá trị từ mảng hoặc object thành các biến riêng lẻ một cách nhanh chóng.
Object Destructuring
const config = {
theme: 'dark',
language: 'vi',
notifications: true,
fontSize: 16
};
// Trước đây — Phải truy cập từng thuộc tính
const theme = config.theme;
const language = config.language;
const notifications = config.notifications;
// Bây giờ — Destructuring gọn gàng
const { theme, language, notifications } = config;
// Đặt tên khác
const { theme: mode, language: lang } = config;
// Giá trị mặc định
const { darkMode = false, fontSize = 14 } = config;
Array Destructuring
const colors = ['#FF5733', '#33FF57', '#3357FF'];
// Trích xuất màu đầu tiên và phần còn lại
const [primary, secondary, ...rest] = colors;
console.log(primary); // '#FF5733'
console.log(secondary); // '#33FF57'
console.log(rest); // ['#3357FF']
// Hoán đổi biến — không cần biến tạm!
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2, 1
Ứng dụng thực tế: Destructuring trong function parameters
// Thay vì
function getUserFullName(user) {
return user.firstName + ' ' + user.lastName;
}
// Dùng destructuring
function getUserFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
// Với giá trị mặc định
function createUser({ name = 'Anonymous', role = 'user' } = {}) {
return { name, role, createdAt: new Date() };
}
4. Spread & Rest Operator — Toán Tử Lan Truyền
Ba dấu chấm (...) trong ES6+ có hai công dụng chính: spread (lan truyền) và rest (thu thập).
Spread — Lan Truyền
// Lan truyền mảng
const original = [1, 2, 3];
const extended = [...original, 4, 5, 6];
console.log(extended); // [1, 2, 3, 4, 5, 6]
// Lan truyền object
const defaults = { theme: 'light', lang: 'en' };
const userSettings = { theme: 'dark', fontSize: 18 };
const settings = { ...defaults, ...userSettings };
console.log(settings); // { theme: 'dark', lang: 'en', fontSize: 18 }
// Sao chép sâu nông (shallow copy)
const originalObj = { a: 1, b: { c: 2 } };
const copy = { ...originalObj };
copy.a = 10;
console.log(originalObj.a); // 1 (không bị ảnh hưởng)
Rest — Thu Thập Tham Số
// Thu thập tham số dư thừa thành mảng
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
// Tách phần đầu và phần còn lại
function firstAndRest(first, ...rest) {
console.log('Phần đầu:', first);
console.log('Phần còn lại:', rest);
}
firstAndRest('a', 'b', 'c', 'd');
// Phần đầu: a
// Phần còn lại: ['b', 'c', 'd']
5. Promises & Async/Await — Xử Lý Bất Đồng Bộ
Trước ES6, xử lý bất đồng bộ trong JavaScript rất phức tạp với callback hell. ES6 giới thiệu Promises, và ES2017 thêm async/await.
Promise Cơ Bản
// Tạo một Promise
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve({ data: 'Hello from API!' });
} else {
reject(new Error('Lỗi kết nối!'));
}
}, 1000);
});
};
// Sử dụng Promise
fetchData()
.then(result => console.log(result))
.catch(error => console.error(error));
Async/Await — Cách Hiện Đại
// Định nghĩa hàm async
async function loadUserData(userId) {
try {
// Đợi API trả về dữ liệu
const response = await fetch(`/api/users/${userId}`);
// Chuyển đổi sang JSON
const user = await response.json();
// Tiếp tục xử lý
console.log(`Tên người dùng: ${user.name}`);
return user;
} catch (error) {
console.error('Không thể tải dữ liệu:', error);
throw error;
}
}
// Gọi hàm async
loadUserData(42).then(user => console.log('Hoàn tất!'));
So sánh: Callback vs Promise vs Async/Await
// ❌ Callback Hell — Khó đọc, khó bảo trì
getUser(id, function(user) {
getPosts(user.id, function(posts) {
getComments(posts[0].id, function(comments) {
console.log(comments);
});
});
});
// ✅ Async/Await — Sạch sẽ, dễ hiểu
async function loadContent(id) {
const user = await getUser(id);
const posts = await getPosts(user.id);
const comments = await getComments(posts[0].id);
console.log(comments);
}
6. Modules — Import & Export
ES6 modules cho phép bạn chia nhỏ code thành các file riêng biệt và tái sử dụng chúng khắp dự án.
Export
// math.js
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// Default export (chỉ có một per file)
export default class Calculator {
constructor() {
this.history = [];
}
calculate(operation, a, b) {
const result = operation(a, b);
this.history.push({ operation, a, b, result });
return result;
}
}
Import
// app.js
// Import default
import Calculator from './math.js';
// Import named
import { PI, add, multiply } from './math.js';
// Import với alias
import { add as sum, multiply as product } from './math.js';
// Import tất cả
import * as MathUtils from './math.js';
// Sử dụng
const calc = new Calculator();
const area = PI * 5 * 5;
const total = sum(10, 20);
7. Classes — Hướng Đối Tượng Hiện Đại
ES6 giới thiệu cú pháp class giúp lập trình hướng đối tượng trở nên dễ tiếp cận hơn.
// Định nghĩa class
class Animal {
// Constructor
constructor(name, sound) {
this.name = name;
this.sound = sound;
}
// Method
speak() {
return `${this.name} says ${this.sound}!`;
}
// Getter
get description() {
return `${this.name} (${this.sound})`;
}
}
// Kế thừa
class Dog extends Animal {
constructor(name, breed) {
super(name, 'Gâu gâu');
this.breed = breed;
}
// Override method
speak() {
return `${super.speak()} 🐕`;
}
fetch(item) {
return `${this.name} chạy đi lấy ${item}!`;
}
}
// Sử dụng
const dog = new Dog('Rex', 'Golden Retriever');
console.log(dog.speak()); // Rex says Gâu gâu! 🐕
console.log(dog.description); // Rex (Gâu gâu)
console.log(dog.fetch('ball')); // Rex chạy đi lấy ball!
8. Map, Set & WeakMap — Cấu Trúc Dữ Liệu Mới
ES6 bổ sung thêm các cấu trúc dữ liệu hữu ích ngoài Array và Object.
Map — Bảng Key-Value
const userRoles = new Map();
userRoles.set('admin', ['read', 'write', 'delete']);
userRoles.set('editor', ['read', 'write']);
userRoles.set('viewer', ['read']);
// Truy cập
console.log(userRoles.get('admin'));
// ['read', 'write', 'delete']
// Duyệt qua Map
for (const [role, permissions] of userRoles) {
console.log(`${role}: ${permissions.join(', ')}`);
}
// Kiểm tra tồn tại
console.log(userRoles.has('moderator')); // false
Set — Tập Hợp Không Trùng Lặp
const tags = new Set(['javascript', 'css', 'html', 'javascript', 'react']);
console.log(tags.size); // 4 — 'javascript' chỉ xuất hiện một lần
tags.add('typescript');
tags.delete('html');
console.log(tags.has('css')); // true
// Chuyển về mảng
const tagArray = [...tags];
console.log(tagArray); // ['javascript', 'css', 'react', 'typescript']
Ứng dụng thực tế: Loại bỏ phần tử trùng lặp
const numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
// Cách cũ
const uniqueOld = [...new Set(numbers)];
console.log(uniqueOld); // [1, 2, 3, 4]
// Hoặc dùng filter
const uniqueFilter = numbers.filter((value, index) =>
numbers.indexOf(value) === index
);
9. Optional Chaining & Nullish Coalescing
Hai tính năng ES2020 giúp xử lý dữ liệu null/undefined an toàn hơn.
Optional Chaining (?.)
const user = {
profile: {
address: {
city: 'Hà Nội'
}
}
};
// Trước đây — Phải kiểm tra từng bước
const city = user && user.profile && user.profile.address && user.profile.address.city;
// Bây giờ — Optional chaining
const city = user?.profile?.address?.city; // 'Hà Nội'
// An toàn ngay cả khi object rỗng
const emptyUser = {};
const street = emptyUser?.profile?.address?.street; // undefined (không lỗi!)
// Gọi method an toàn
const result = user?.profile?.getName?.();
Nullish Coalescing (??)
const config = {
title: '',
subtitle: null,
version: 0
};
// ?? chỉ trả về fallback khi value là null hoặc undefined
const title = config.title ?? 'Default Title'; // '' (rỗng, không phải null)
const subtitle = config.subtitle ?? 'No Subtitle'; // 'No Subtitle'
const version = config.version ?? 1; // 0 (số 0, không phải null)
// Khác với || (OR logic)
const titleAlt = config.title || 'Default Title'; // 'Default Title' ❌
// Vì '' được coi là falsy trong ||
10. For…of Loop — Duyệt Vòng Lặp Hiện Đại
const fruits = ['Táo', 'Cam', 'Chanh', 'Nho'];
// forEach — Không thể break
fruits.forEach(fruit => {
if (fruit === 'Chanh') return; // Chỉ bỏ qua iteration này
console.log(fruit);
});
// For...of — Có thể break và continue
for (const fruit of fruits) {
if (fruit === 'Chanh') break;
console.log(fruit);
}
// Táo
// Cam
// Duyệt Map
const scores = new Map([['An', 9], ['Bình', 8], ['Chi', 10]]);
for (const [name, score] of scores) {
console.log(`${name}: ${score}/10`);
}
Tổng Kết — Lộ Trình Học Tập
Để làm chủ ES6+, bạn nên học theo thứ tự sau:
| Thứ tự | Tính năng | Độ khó | Mức độ sử dụng |
|---|---|---|---|
| 1 | Template Literals | Dễ | Rất cao |
| 2 | Arrow Functions | Dễ | Rất cao |
| 3 | Destructuring | Trung bình | Cao |
| 4 | Spread/Rest | Trung bình | Cao |
| 5 | Let/Const | Dễ | Rất cao |
| 6 | Modules | Trung bình | Cao |
| 7 | Async/Await | Trung bình | Rất cao |
| 8 | Classes | Trung bình | Cao |
| 9 | Map/Set | Dễ | Trung bình |
| 10 | Optional Chaining | Dễ | Cao |
Hãy bắt đầu với những tính năng cơ bản nhất (arrow functions, template literals, destructuring) và dần dần khám phá những tính năng nâng cao hơn. Thực hành mỗi ngày trên các dự án nhỏ sẽ giúp bạn ghi nhớ lâu hơn bất kỳ lý thuyết nào.
Câu Hỏi Thường Gặp
Câu hỏi thường gặp ở cuối bài viết đã được liệt kê trong phần frontmatter phía trên. Dưới đây là tóm tắt nhanh:
- ES6 là gì? Phiên bản ECMAScript 2015, giới thiệu nhiều tính năng hiện đại cho JavaScript.
- Có cần Babel không? Hầu hết trình duyệt hiện đại đã hỗ trợ đầy đủ ES6+. Chỉ cần Babel nếu hỗ trợ trình duyệt cũ.
- let, const, var khác nhau thế nào?
constkhông thể gán lại,letcó thể nhưng chỉ trong block scope,varcó function scope (tránh dùng). - Khi nào dùng async/await? Luôn ưu tiên async/await cho code mới, trừ khi cần xử lý song song với
Promise.all(). - Arrow function có luôn tốt hơn? Không — tránh dùng arrow function làm phương thức object vì vấn đề với
this.
Bạn đã áp dụng những tính năng ES6+ nào trong dự án của mình? Chia sẻ trải nghiệm của bạn trong phần bình luận bên dưới!
Theo dõi Devs2.org để không bỏ lỡ những bài viết mới nhất về web development!