Hiểu Sâu Về Giải Cấu Trúc (Destructuring Assignment) Trong ECMAScript 6

Khái niệm cơ bản

ECMAScript 6 (ES6) giới thiệu một cú pháp mạnh mẽ cho phép trích xuất dữ liệu từ mảng hoặc đối tượng theo mô hình xác định trước để gán cho các biến. Quá trình này được gọi là giải cấu trúc (Destructuring Assignment).

Thay vì khai báo biến độc lập và gán giá trị thủ công như trong ES5:

const x = 100;
const y = 200;
const z = 300;

Với ES6, chúng ta có thể viết ngắn gọn hơn bằng cách sử dụng mẫu cấu trúc bên trái dấu bằng:

const [x, y, z] = [100, 200, 300];
// Cú pháp trên tự động phân phối giá trị theo vị trí từ mảng sang biến tương ứng.

Xử lý giá trị mặc định

Tính năng này hỗ trợ đặt giá trị dự phòng. Giá trị mặc định chỉ được áp dụng khi giá trị tương ứng trong cấu trúc nguồn bị thiếu hoặc chính xác bằng undefined.

const [isActive = true] = [];
console.log(isActive); // true

const [prefix, suffix = 'default'] = ['Hello'];
console.log(prefix, suffix); // Hello default

const [val1, val2 = 'fallback'] = ['A', undefined];
console.log(val1, val2); // A fallback

Cần lưu ý rằng nếu phần tử là null, giá trị mặc định sẽ không kích hoạt vì null !== undefined:

const [num = 5] = [undefined];
const [obj = {}] = [null];
console.log(num); // 5
console.log(obj); // null

Một điểm đặc biệt là giá trị mặc định có thể tham chiếu đến các biến đã được khai báo trước đó trong cùng cú pháp, miễn là biến đó tồn tại tại thời điểm đánh giá:

// Hợp lệ: a được định nghĩa trước b
const [a = 1, b = a] = []; 
console.log(a, b); // 1 1

// Không hợp lệ: e cố gắng dùng i trước khi i được khai báo
// const [e = i, i = 1] = []; // ReferenceError: i is not defined

Giải cấu trúc Mảng (Array)

Khi làm việc với mảng, thứ tự là yếu tố quyết định. Biến ở phía trái cần khớp vị trí với giá trị ở phía phải.

const palette = ["#FF0000", "#00FF00", "#0000FF"];
const [first, second] = palette;
console.log(first);  // "#FF0000"
console.log(second); // "#00FF00"

Bạn cũng có thể bỏ qua các phần tử không cần thiết bằng dấu phẩy rời rạc:

const colors = ["red", "green", "blue"];
const [, , blueColor] = colors;
console.log(blueColor); // "blue"

Một ứng dụng phổ biến là hoán đổi giá trị hai biến mà không cần biến trung gian:

let alpha = 10;
let beta = 5;
[alpha, beta] = [beta, alpha];
console.log(alpha, beta); // 5, 10

Nếu số lượng biến lớn hơn số lượng giá trị trong mảng, các biến thừa sẽ nhận giá trị undefined:

const [m, n, o] = [1];
console.log(m); // 1
console.log(o); // undefined

Tuy nhiên, nếu nhiều giá trị hơn biến, phần còn lại sẽ bị bỏ qua.

Giải cấu trúc Đối tượng (Object)

Khác với mảng, việc gán giá trị trong đối tượng phụ thuộc vào tên thuộc tính (key) chứ không phải thứ tự.

const userInfo = { userName: 'Minh', age: 20, gender: 'Male' };
const { userName, age } = userInfo;
console.log(userName, age); // Minh 20

Bạn có thể ánh xạ thuộc tính thành biến có tên khác bằng dấu hai chấm (: ):

const { name: nickname, role } = { name: 'Admin', role: 'Super' };
console.log(nickname); // Admin

Thứ tự các biến trong mẫu giải cấu trúc không ảnh hưởng đến kết quả cuối cùng miễn là tên khớp với key của đối tượng.

Hệ thống lồng ghép và Hỗn hợp

Destructuring hỗ trợ cấu trúc sâu và hỗn hợp giữa mảng và đối tượng.

const data = {
  header: { status: 200 },
  items: [
    'Item A',
    { id: 99 }
  ]
};

// Trích xuất cả property 'items' và value bên trong nó
const { header, items: [label, details] } = data;
console.log(header.status); // 200
console.log(label);         // Item A
console.log(details.id);    // 99

Cấu trúc này rất hữu ích khi xử lý dữ liệu trả về từ API phức tạp.

Ví dụ với chuỗi và các tình huống thực tiễn

Kể cả chuỗi ký tự cũng có thể xem như đối tượng giống mảng để giải cấu trúc:

const str = 'ABC';
const [firstChar, lastChar] = [str[0], str[str.length - 1]];
// Hoặc trực tiếp từ chuỗi
const [x, y] = 'AB'; 
console.log(x); // "A"

Bên cạnh đó, nhờ có thuộc tính length, ta có thể lấy độ dài chuỗi:

const { length: len } = 'DemoString';
console.log(len); // 10

Lợi ích ứng dụng thực tế

  • Hoán đổi biến: Loại bỏ biến tạm trung gian.
  • Hàm trả về nhiều giá trị: Đóng gói kết quả trả về trong mảng/đối tượng và mở ra ngay khi gọi.
  • Tham số hàm: Định nghĩa tham số mặc định và cấu trúc ngay trong danh sách đối số.
  • Xử lý JSON: Lấy nhanh các trường dữ liệu cần thiết từ phản hồi API.
  • Cập nhật cấu trúc Map: Kết hợp Iterator để duyệt và lấy key/value dễ dàng.
  • Nhập module: Chỉ định rõ các phương thức cần import từ thư viện ngoài thay vì nạp toàn bộ.

Thẻ: JavaScript es6 destructuring array-manipulation object-structured

Đăng vào ngày 29 tháng 5 lúc 17:39