Hai cấu trúc dữ liệu được sử dụng nhiều nhất trong JavaScript là ObjectArray.

Các đối tượng cho phép chúng ta tạo một thực thể duy nhất lưu trữ các mục dữ liệu theo khóa và các mảng cho phép chúng ta thu thập các phần tử dữ liệu vào một bộ sưu tập theo thứ tự.

Nhưng khi chúng ta chuyển chúng cho một hàm, nó có thể không cần một đối tượng / mảng, mà là các phần riêng lẻ.

Phá huỷ(phân rã) giá trị là một cú pháp đặc biệt cho phép chúng ta giải phóng các mảng hoặc đối tượng của mình thành một loạt các biến, vì đôi khi điều đó thuận tiện hơn. Phá hủy cấu trúc cũng hoạt động tuyệt vời với các hàm phức tạp có nhiều tham số, giá trị mặc định, v.v.

1. Phân rã mảng

Một ví dụ về cách mảng bị phá hủy thành các biến:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

// we have an array with the name and surname
let arr = ["Ilya", "Kantor"]

// destructuring assignment
// sets firstName = arr[0]
// and surname = arr[1]
let [firstName, surname] = arr;

alert(firstName); // Ilya
alert(surname);  // Kantor

Bây giờ chúng ta có thể làm việc với các biến thay vì các thành viên mảng.

Nó trông tuyệt vời khi kết hợp với splithoặc các phương thức trả về mảng khác:

let [firstName, surname] = "Ilya Kantor".split(' ');

Cơ cấu phân rã giá trị không có nghĩa là phá hoại.

Nó được gọi là chuyển nhượng, bởi vì nó phá hủy bằng cách sao chép các mục(phần tử) vào các biến. Nhưng bản thân mảng không được sửa đổi.

Đây chỉ là một cách viết ngắn hơn:

// let [firstName, surname] = arr;
let firstName = arr[0];
let surname = arr[1];

Bỏ qua các yếu tố sử dụng dấu phẩy

Các phần tử không mong muốn của mảng cũng có thể được loại bỏ thông qua dấu phẩy thừa:

// second element is not needed
let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];

alert( title ); // Consul

Trong đoạn code trên, phần tử thứ hai của mảng bị bỏ qua, phần tử thứ ba được gán cho titlevà phần còn lại của các mục mảng cũng bị bỏ qua (vì không có biến nào cho chúng).

Hoạt động với bất kỳ lần lặp nào ở phía bên phải

Thật ra, chúng ta có thể sử dụng nó với bất kỳ lần lặp nào, không chỉ các mảng:

let [a, b, c] = "abc"; // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3]);

Gán cho bất cứ điều gì ở phía bên trái

Chúng ta có thể sử dụng bất kỳ nhiệm vụ chuyển nhượng nào ở bên trái.

Ví dụ, một thuộc tính đối tượng:

let user = {};
[user.name, user.surname] = "Ilya Kantor".split(' ');

alert(user.name); // Ilya

Vòng lặp với .entries()

Trong chương trước, chúng ta đã thấy phương thức Object.entries(obj) .

Chúng ta có thể sử dụng nó với việc hủy bỏ để lặp lại các khóa và giá trị của một đối tượng:

let user = {
  name: "John",
  age: 30
};

// loop over keys-and-values
for (let [key, value] of Object.entries(user)) {
  alert(`${key}:${value}`); // name:John, then age:30
}

và tương tự cho Map:

let user = new Map();
user.set("name", "John");
user.set("age", "30");

for (let [key, value] of user) {
  alert(`${key}:${value}`); // name:John, then age:30
}

Hoán đổi biến

Một mẹo nổi tiếng để hoán đổi giá trị của hai biến:

let guest = "Jane";
let admin = "Pete";

// Swap values: make guest=Pete, admin=Jane
[guest, admin] = [admin, guest];

alert(`${guest} ${admin}`); // Pete Jane (successfully swapped!)

Ở đây chúng ta tạo một mảng tạm thời gồm hai biến và ngay lập tức phá hủy nó theo thứ tự hoán đổi.

Chúng ta có thể trao đổi nhiều hơn hai biến theo cách này.

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

### The rest '...'

If we want not just to get first values, but also to gather all that follows -- we can add one more parameter that gets "the rest" using three dots `"..."`:

```js run
let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];

alert(name1); // Julius
alert(name2); // Caesar

// Note that type of `rest` is Array.
alert(rest[0]); // Consul
alert(rest[1]); // of the Roman Republic
alert(rest.length); // 2

Giá trị của restlà mảng của các phần tử mảng còn lại. Chúng ta có thể sử dụng bất kỳ tên biến nào khác thay thế rest, chỉ cần đảm bảo rằng nó có ba dấu chấm trước nó và đi cuối cùng trong phá hủy.

Giá trị mặc định

Nếu có ít giá trị trong mảng hơn các biến trong quá trình gán, sẽ không có lỗi. Giá trị vắng mặt được coi là không xác định:

let [firstName, surname] = [];

alert(firstName); // undefined
alert(surname); // undefined

Nếu chúng ta muốn một giá trị mặc định thay thế giá trị còn thiếu, chúng ta có thể cung cấp nó bằng cách sử dụng =:

// default values
let [name = "Guest", surname = "Anonymous"] = ["Julius"];

alert(name);    // Julius (from array)
alert(surname); // Anonymous (default used)

Giá trị mặc định có thể là các biểu thức phức tạp hơn hoặc thậm chí các lệnh gọi hàm. Chúng chỉ được đánh giá nếu giá trị không được cung cấp.

Ví dụ, ở đây chúng ta sử dụng hàmprompt để gán hai giá trị mặc định. Nhưng nó sẽ chỉ chạy cho biến còn thiếu:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

// runs only prompt for surname
let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"];

alert(name);    // Julius (from array)
alert(surname); // whatever prompt gets

2. Phân rã đối tượng

Nhiệm vụ phân rã cũng hoạt động với các đối tượng.

Cú pháp cơ bản là:

let {var1, var2} = {var1:…, var2:…}

Chúng tôi có một đối tượng hiện có ở phía bên phải, mà chúng tôi muốn chia thành các biến. Phía bên trái chứa một mô hình cho các thuộc tính tương ứng. Trong trường hợp đơn giản, đó là một danh sách các tên biến trong {...}.

Ví dụ:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

let options = {
  title: "Menu",
  width: 100,
  height: 200
};

let {title, width, height} = options;

alert(title);  // Menu
alert(width);  // 100
alert(height); // 200

Thuộc tính options.title, options.widthoptions.heightđược gán cho các biến tương ứng. Thứ tự không quan trọng. Điều này cũng hoạt động:

// changed the order in let {...}
let {height, width, title} = { title: "Menu", height: 200, width: 100 }

Mẫu ở phía bên trái có thể phức tạp hơn và chỉ định ánh xạ giữa các thuộc tính và biến.

Ví dụ, nếu chúng ta muốn gán một thuộc tính cho một biến có tên khác options.widthđể đi vào biến có tên w, thì chúng ta có thể đặt thuộc tính đó bằng dấu hai chấm:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

let options = {
  title: "Menu",
  width: 100,
  height: 200
};

// { sourceProperty: targetVariable }
let {width: w, height: h, title} = options;

// width -> w
// height -> h
// title -> title

alert(title);  // Menu
alert(w);      // 100
alert(h);      // 200

Dấu hai chấm cho thấy những gì: đi đâu. Trong ví dụ trên, thuộc tính widthđi tới w, thuộc tính heightđi đến htitleđược gán cho biến cùng tên.

Đối với các thuộc tính có khả năng bị thiếu, chúng ta có thể đặt các giá trị mặc định bằng cách sử dụng "=", như thế này:

let options = {
  title: "Menu"
};

let {width = 100, height = 200, title} = options;

alert(title);  // Menu
alert(width);  // 100
alert(height); // 200

Giống như với các mảng hoặc tham số hàm, các giá trị mặc định có thể là bất kỳ biểu thức hoặc thậm chí các lệnh gọi hàm. Họ sẽ được đánh giá nếu giá trị không được cung cấp.

Trong code dưới đây promptyêu cầu width, nhưng không cho title:

let options = {
  title: "Menu"
};

let {width = prompt("width?"), title = prompt("title?")} = options;

alert(title);  // Menu
alert(width);  // (whatever the result of prompt is)

Chúng ta cũng có thể kết hợp cả dấu hai chấm và đẳng thức:

let options = {
  title: "Menu"
};

let {width: w = 100, height: h = 200, title} = options;

alert(title);  // Menu
alert(w);      // 100
alert(h);      // 200

Nếu chúng ta có một đối tượng phức tạp với nhiều thuộc tính, chúng ta chỉ có thể trích xuất những gì chúng ta cần:

let options = {
  title: "Menu",
  width: 100,
  height: 200
};

// only extract title as a variable
let { title } = options;

alert(title); // Menu

Các mẫu “…”

Điều gì xảy ra nếu đối tượng có nhiều thuộc tính hơn chúng ta có các biến? Chúng ta có thể lấy một số và sau đó chỉ định phần còn lại không?

Chúng ta có thể sử dụng mẫu còn lại, giống như chúng ta đã làm với mảng. Nó không được hỗ trợ bởi một số trình duyệt cũ hơn (IE), nhưng hoạt động trong các trình duyệt hiện đại.

Nó trông như thế này:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

let options = {
  title: "Menu",
  height: 200,
  width: 100
};

// title = property named title
// rest = object with the rest of properties
let {title, ...rest} = options;

// now title="Menu", rest={height: 200, width: 100}
alert(rest.height);  // 200
alert(rest.width);   // 100

Nếu không có let

Trong các ví dụ trên, các biến được khai báo ngay trong qúa trình gán : let {…} = {…}. Tất nhiên, chúng ta cũng có thể sử dụng các biến hiện có mà không cần let. Nhưng có một nhược điểm.

Điều này sẽ không hoạt động:

let title, width, height;

// error in this line
{title, width, height} = {title: "Menu", width: 200, height: 100};

Vấn đề là JavaScript xử lý {...}luồng code chính (không nằm trong biểu thức khác) dưới dạng khối code. Các khối code như vậy có thể được sử dụng để nhóm các câu lệnh, như thế này:

{
  // a code block
  let message = "Hello";
  // ...
  alert( message );
}

Vì vậy, ở đây JavaScript giả định rằng chúng ta có một khối code, đó là lý do tại sao có lỗi. Chúng ta muốn phân rã.

Để hiển thị JavaScript rằng đó không phải là một khối code, chúng ta có thể gói biểu thức trong ngoặc đơn (...):

let title, width, height;

// okay now
({title, width, height} = {title: "Menu", width: 200, height: 100});

alert( title ); // Menu

3. Phân rã lồng nhau

Nếu một đối tượng hoặc một mảng chứa các đối tượng và mảng lồng nhau, chúng ta có thể sử dụng các mẫu bên trái phức tạp hơn để trích xuất các phần sâu hơn.

Trong code dưới đây, các option có một đối tượng khác bên trong là thuộc tính size và một mảng trong các mục thuộc tính. Mẫu ở bên trái của việc gán có cùng cấu trúc để trích xuất các giá trị từ chúng:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

let options = {
  size: {
    width: 100,
    height: 200
  },
  items: ["Cake", "Donut"],
  extra: true
};

// destructuring assignment split in multiple lines for clarity
let {
  size: { // put size here
    width,
    height
  },
  items: [item1, item2], // assign items here
  title = "Menu" // not present in the object (default value is used)
} = options;

alert(title);  // Menu
alert(width);  // 100
alert(height); // 200
alert(item1);  // Cake
alert(item2);  // Donut

Tất cả các thuộc tính của đối tượng tùy chọn ngoại trừ phần phụ không có ở phần bên trái, được gán cho các biến tương ứng:

Cuối cùng, chúng ta có width, height, item1, item2 và title từ giá trị mặc định

Lưu ý rằng không có biến cho size và item, vì chúng ta lấy nội dung của chúng thay thế.

4. Một tham số hàm

Đôi khi một hàm có nhiều tham số, hầu hết là tùy chọn. Điều đó đặc biệt đúng với giao diện người dùng. Hãy tưởng tượng một hàm tạo ra một menu. Nó có thể có chiều rộng, chiều cao, tiêu đề, danh sách vật phẩm, v.v.

Đây là một cách tôi để viết hàm như vậy:

function showMenu(title = "Untitled", width = 200, height = 100, items = []) {
  // ...
}

Trong thực tế, vấn đề là làm thế nào để nhớ thứ tự lập luận. Thông thường các IDE cố gắng giúp chúng ta, đặc biệt là nếu code được ghi chép tốt, nhưng vẫn còn một vấn đề khác là làm thế nào để gọi một hàm khi hầu hết các tham số đều được truyền.

Như thế này?

// undefined where default values are fine
showMenu("My Menu", undefined, undefined, ["Item1", "Item2"])

Thật là xấu xí. Và trở nên không thể đọc được khi chúng ta xử lý nhiều tham số hơn.

Phân rã để giúp làm điều này

Chúng ta có thể truyền tham số dưới dạng một đối tượng và hàm ngay lập tức phân rã chúng thành các biến:

// we pass object to function
let options = {
  title: "My menu",
  items: ["Item1", "Item2"]
};

// ...and it immediately expands it to variables
function showMenu({title = "Untitled", width = 200, height = 100, items = []}) {
  // title, items – taken from options,
  // width, height – defaults used
  alert( `${title} ${width} ${height}` ); // My Menu 200 100
  alert( items ); // Item1, Item2
}

showMenu(options);

Chúng ta cũng có thể sử dụng phân ra phức tạp hơn với các đối tượng lồng nhau và ánh xạ dấu hai chấm:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

let options = {
  title: "My menu",
  items: ["Item1", "Item2"]
};

function showMenu({
  title = "Untitled",
  width: w = 100,  // width goes to w
  height: h = 200, // height goes to h
  items: [item1, item2] // items first element goes to item1, second to item2
}) {
  alert( `${title} ${w} ${h}` ); // My Menu 100 200
  alert( item1 ); // Item1
  alert( item2 ); // Item2
}

showMenu(options);

Cú pháp đầy đủ giống như đối với một nhiệm vụ hủy diệt:

function({
  incomingProperty: varName = defaultValue
  ...
})

Sau đó, đối với một đối tượng của tham số, sẽ có một biến varNamecho thuộc tính incomingProperty, defaultValuetheo mặc định.

Xin lưu ý rằng các giả định phân rã đó showMenu(). Nếu chúng ta muốn tất cả các giá trị theo mặc định, thì chúng ta nên chỉ định một đối tượng trống:

showMenu({}); // ok, all values are default

showMenu(); // this would give an error

Chúng ta có thể khắc phục điều này bằng cách tạo {}giá trị mặc định cho toàn bộ đối tượng của tham số:

function showMenu({ title = "Menu", width = 100, height = 200 } = {}) {
  alert( `${title} ${width} ${height}` );
}

showMenu(); // Menu 100 200

Trong đoạn code trên, toàn bộ đối tượng đối số là {}theo mặc định, vì vậy luôn có thứ gì đó để phân rã.

5. Tóm lược

  • Phân rã cấu trúc cho phép ánh xạ ngay lập tức một đối tượng hoặc mảng lên nhiều biến.
  • Cú pháp đối tượng đầy đủ:
  • let {prop : varName = default, ...rest} = object

Điều này có nghĩa là thuộc tính propnên đi vào biến varNamevà, nếu không có thuộc tính đó tồn tại, thì defaultgiá trị sẽ được sử dụng.

Các thuộc tính đối tượng không có ánh xạ được sao chép vào đối tượng rest.

Cú pháp mảng đầy đủ:

let [item1 = default, item2, ...rest] = array

Mục đầu tiên đi đến item1; thứ hai đi vào item2, tất cả phần còn lại sẽ gán cho mảng rest.

Có thể trích xuất dữ liệu từ các mảng / đối tượng lồng nhau, vì bên trái phải có cùng cấu trúc với bên phải.

Full series tự học Javascript từ cơ bản tới nâng cao tại đây nha.

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!