Thứ ba, 12/05/2020 | 00:00 GMT+7

Hiểu về cấu trúc hủy, tham số khôi phục và cú pháp trải rộng trong JavaScript

Nhiều tính năng mới để làm việc với mảngđối tượng đã được cung cấp cho ngôn ngữ JavaScript kể từ Phiên bản 2015 của đặc tả ECMAScript. Một vài trong số những điều đáng chú ý mà bạn sẽ tìm hiểu trong bài viết này là cấu trúc hủy , tham số nghỉ và cú pháp lây lan . Các tính năng này cung cấp nhiều cách truy cập trực tiếp hơn vào các thành viên của một mảng hoặc một đối tượng và có thể làm cho việc làm việc với các cấu trúc dữ liệu này nhanh hơn và ngắn gọn hơn.

Nhiều ngôn ngữ khác không có cú pháp tương ứng cho cấu trúc, tham số phần còn lại và lây lan, vì vậy những tính năng này có thể có đường cong học tập cho cả nhà phát triển JavaScript mới và những người đến từ ngôn ngữ khác. Trong bài viết này, bạn sẽ học cách hủy cấu trúc các đối tượng và mảng, cách sử dụng toán tử spread để extract các đối tượng và mảng cũng như cách sử dụng các tham số còn lại trong các lời gọi hàm.

Phá hủy

Gán hủy cấu trúc là một cú pháp cho phép bạn gán các thuộc tính đối tượng hoặc các mục mảng dưới dạng các biến. Điều này có thể làm giảm đáng kể các dòng mã cần thiết để thao tác dữ liệu trong các cấu trúc này. Có hai kiểu hủy cấu trúc: Cấu trúc đối tượng và hủy cấu trúc mảng.

Cấu trúc đối tượng

Cấu trúc đối tượng cho phép bạn tạo các biến mới bằng cách sử dụng một thuộc tính đối tượng làm giá trị.

Hãy xem xét ví dụ này, một đối tượng đại diện cho một ghi chú có id , titledate :

const note = {   id: 1,   title: 'My first note',   date: '01/01/1970', } 

Theo truyền thống, nếu bạn muốn tạo một biến mới cho từng thuộc tính, bạn sẽ phải chỉ định từng biến riêng lẻ, với rất nhiều lần lặp lại:

// Create variables from the Object properties const id = note.id const title = note.title const date = note.date 

Với cấu trúc hủy đối tượng, tất cả điều này có thể được thực hiện trong một dòng. Bằng cách đặt mỗi biến trong dấu ngoặc nhọn {} , JavaScript sẽ tạo các biến mới từ mỗi thuộc tính có cùng tên:

// Destructure properties into variables const { id, title, date } = note 

Bây giờ, console.log() các biến mới:

console.log(id) console.log(title) console.log(date) 

Bạn sẽ nhận được các giá trị thuộc tính ban đầu dưới dạng kết quả :

Output
1 My first note 01/01/1970

Lưu ý: Việc hủy cấu trúc một đối tượng không sửa đổi đối tượng ban đầu. Bạn vẫn có thể gọi note root với tất cả các mục của nó còn nguyên vẹn.

Phép gán mặc định cho việc hủy cấu trúc đối tượng tạo ra các biến mới có cùng tên với thuộc tính đối tượng. Nếu bạn không muốn biến mới có tên giống như tên thuộc tính, bạn cũng có tùy chọn đổi tên biến mới bằng cách sử dụng dấu hai chấm ( : ) để quyết định một cái tên mới, như đã thấy với noteId trong những điều sau đây:

// Assign a custom name to a destructured value const { id: noteId, title, date } = note 

Đăng biến mới noteId ra cửa sổ Console:

console.log(noteId) 

Bạn sẽ nhận được kết quả sau:

Output
1

Bạn cũng có thể hủy cấu trúc các giá trị đối tượng lồng nhau. Ví dụ: cập nhật đối tượng note để có đối tượng author lồng nhau:

const note = {   id: 1,   title: 'My first note',   date: '01/01/1970',   author: {     firstName: 'Sherlock',     lastName: 'Holmes',   }, } 

Đến đây bạn có thể hủy cấu trúc note , sau đó hủy cấu trúc lại để tạo các biến từ các thuộc tính của author :

// Destructure nested properties const {   id,   title,   date,   author: { firstName, lastName }, } = note 

Tiếp theo, ghi lại các biến mới firstNamelastName bằng cách sử dụng các ký tự mẫu :

console.log(`${firstName} ${lastName}`) 

Điều này sẽ cho kết quả sau:

Output
Sherlock Holmes

Lưu ý trong ví dụ này, mặc dù bạn có quyền truy cập vào nội dung của đối tượng author , nhưng bản thân đối tượng author không thể truy cập được. Để truy cập một đối tượng cũng như các giá trị lồng nhau của nó, bạn sẽ phải khai báo chúng một cách riêng biệt:

// Access object and nested values const {   author,   author: { firstName, lastName }, } = note  console.log(author) 

Mã này sẽ xuất đối tượng author :

Output
{firstName: "Sherlock", lastName: "Holmes"}

Việc hủy cấu trúc một đối tượng không chỉ hữu ích để giảm số lượng mã mà bạn phải viết; nó cũng cho phép bạn nhắm đến quyền truy cập của bạn vào các thuộc tính mà bạn quan tâm.

Cuối cùng, cấu trúc hủy được dùng để truy cập các thuộc tính đối tượng của các giá trị nguyên thủy. Ví dụ: String là một đối tượng toàn cục cho các chuỗi và có thuộc tính length :

const { length } = 'A string' 

Thao tác này sẽ tìm thuộc tính độ dài vốn có của một chuỗi và đặt nó bằng với biến length . length log để xem điều này có hiệu quả không:

console.log(length) 

Bạn sẽ nhận được kết quả sau:

Output
8

Chuỗi A string đã được chuyển đổi hoàn toàn thành một đối tượng ở đây để truy xuất thuộc tính length .

Cấu trúc mảng

Cấu trúc mảng cho phép bạn tạo các biến mới bằng cách sử dụng một mục mảng làm giá trị. Hãy xem xét ví dụ này, một mảng với các phần khác nhau của ngày:

const date = ['1970', '12', '01'] 

Mảng trong JavaScript được đảm bảo duy trì thứ tự của chúng, vì vậy trong trường hợp này, index đầu tiên sẽ luôn là năm, index thứ hai sẽ là tháng, v.v. Biết được điều này, bạn có thể tạo các biến từ các mục trong mảng:

// Create variables from the Array items const year = date[0] const month = date[1] const day = date[2] 

Nhưng làm điều này theo cách thủ công có thể chiếm nhiều dung lượng trong mã của bạn. Với cấu trúc hủy mảng, bạn có thể extract các giá trị từ mảng theo thứ tự và gán chúng cho các biến của riêng chúng, như sau:

// Destructure Array values into variables const [year, month, day] = date 

Bây giờ ghi lại các biến mới:

console.log(year) console.log(month) console.log(day) 

Bạn sẽ nhận được kết quả sau:

Output
1970 12 01

Có thể bỏ qua các giá trị bằng cách để trống cú pháp cấu trúc giữa các dấu phẩy:

// Skip the second item in the array const [year, , day] = date  console.log(year) console.log(day) 

Chạy điều này sẽ cung cấp giá trị của yearday :

Output
1970 01

Các mảng lồng nhau cũng có thể bị hủy. Đầu tiên, hãy tạo một mảng lồng nhau:

// Create a nested array const nestedArray = [1, 2, [3, 4], 5] 

Sau đó, hủy cấu trúc mảng đó và ghi lại các biến mới:

// Destructure nested items const [one, two, [three, four], five] = nestedArray  console.log(one, two, three, four, five) 

Bạn sẽ nhận được kết quả sau:

Output
1 2 3 4 5

Cú pháp hủy cấu trúc có thể được áp dụng để hủy cấu trúc các tham số trong một hàm. Để kiểm tra điều này, bạn sẽ hủy cấu trúc các keysvalues trong Object.entries() .

Đầu tiên, khai báo đối tượng note :

const note = {   id: 1,   title: 'My first note',   date: '01/01/1970', } 

Với đối tượng này, bạn có thể liệt kê các cặp key-value bằng cách cấu trúc các đối số khi chúng được chuyển đến phương thức forEach() :

// Using forEach Object.entries(note).forEach(([key, value]) => {   console.log(`${key}: ${value}`) }) 

Hoặc bạn có thể thực hiện điều tương tự bằng cách sử dụngvòng lặp for :

// Using a for loop for (let [key, value] of Object.entries(note)) {   console.log(`${key}: ${value}`) } 

Dù bằng cách nào, bạn sẽ nhận được những điều sau:

Output
id: 1 title: My first note date: 01/01/1970

Cấu trúc hủy đối tượng và hủy cấu trúc mảng có thể được kết hợp trong một nhiệm vụ hủy cấu trúc duy nhất. Các tham số mặc định cũng được dùng với cấu trúc hủy, như được thấy trong ví dụ này đặt ngày mặc định thành new Date() .

Đầu tiên, khai báo đối tượng note :

const note = {   title: 'My first note',   author: {     firstName: 'Sherlock',     lastName: 'Holmes',   },   tags: ['personal', 'writing', 'investigations'], } 

Sau đó, hủy cấu trúc đối tượng, đồng thời cài đặt một biến date mới với mặc định là new Date() :

const {   title,   date = new Date(),   author: { firstName },   tags: [personalTag, writingTag], } = note  console.log(date) 

console.log(date) sau đó sẽ đưa ra kết quả tương tự như sau:

Output
Fri May 08 2020 23:53:49 GMT-0500 (Central Daylight Time)

Như được trình bày trong phần này, cú pháp gán hàm hủy cấu trúc bổ sung nhiều tính linh hoạt cho JavaScript và cho phép bạn viết mã ngắn gọn hơn. Trong phần tiếp theo, bạn sẽ thấy cú pháp lây lan được dùng như thế nào để mở rộng cấu trúc dữ liệu vào các mục dữ liệu cấu thành của chúng.

Lây lan

Cú pháp Spread ( ... ) là một bổ sung hữu ích khác cho JavaScript để làm việc với mảng, đối tượng và lời gọi hàm. Spread cho phép các đối tượng và các file lặp (chẳng hạn như mảng) được extract hoặc mở rộng, được dùng để tạo các bản sao nông của cấu trúc dữ liệu nhằm tăng tính dễ thao tác dữ liệu.

Trải rộng với Mảng

Spread có thể đơn giản hóa các việc thông thường với mảng. Ví dụ: giả sử bạn có hai mảng và muốn kết hợp chúng:

// Create an Array const tools = ['hammer', 'screwdriver'] const otherTools = ['wrench', 'saw'] 

Ban đầu, bạn sẽ sử dụng concat() để nối hai mảng:

// Concatenate tools and otherTools together const allTools = tools.concat(otherTools) 

Đến đây bạn cũng có thể sử dụng spread để extract các mảng thành một mảng mới:

// Unpack the tools Array into the allTools Array const allTools = [...tools, ...otherTools]  console.log(allTools) 

Chạy điều này sẽ cung cấp những điều sau:

Output
["hammer", "screwdriver", "wrench", "saw"]

Điều này có thể đặc biệt hữu ích với tính bất biến. Ví dụ: bạn có thể đang làm việc với một ứng dụng có users được lưu trữ trong một mảng đối tượng:

// Array of users const users = [   { id: 1, name: 'Ben' },   { id: 2, name: 'Leslie' }, ] 

Bạn có thể sử dụng push để sửa đổi mảng hiện có và thêm user mới, đây sẽ là tùy chọn có thể thay đổi:

// A new user to be added const newUser = { id: 3, name: 'Ron' }  users.push(newUser) 

Nhưng điều này thay đổi mảng user , mà ta có thể cần giữ lại.

Spread cho phép bạn tạo một mảng mới từ mảng hiện có và thêm một mục mới vào cuối:

const updatedUsers = [...users, newUser]  console.log(users) console.log(updatedUsers) 

Bây giờ mảng mới, updatedUsers , có user mới, nhưng mảng users ban đầu vẫn không thay đổi:

Output
[{id: 1, name: "Ben"} {id: 2, name: "Leslie"}] [{id: 1, name: "Ben"} {id: 2, name: "Leslie"} {id: 3, name: "Ron"}]

Tạo bản sao dữ liệu thay vì thay đổi dữ liệu hiện có có thể giúp ngăn chặn những thay đổi không mong muốn. Trong JavaScript, khi bạn tạo một đối tượng hoặc mảng và gán nó cho một biến khác, bạn không tạo một đối tượng mới — bạn đang truyền một tham chiếu.

Lấy ví dụ này, trong đó một mảng được tạo và gán cho một biến khác:

// Create an Array const originalArray = ['one', 'two', 'three']  // Assign Array to another variable const secondArray = originalArray 

Xóa mục cuối cùng của Mảng thứ hai sẽ sửa đổi mục đầu tiên:

// Remove the last item of the second Array secondArray.pop()  console.log(originalArray) 

Điều này sẽ cho kết quả:

Output
["one", "two"]

Spread cho phép bạn tạo bản sao nông của một mảng hoặc đối tượng, nghĩa là bất kỳ thuộc tính cấp cao nhất nào cũng sẽ được sao chép, nhưng các đối tượng lồng nhau sẽ vẫn được chuyển qua tham chiếu. Đối với các mảng hoặc đối tượng đơn giản, một bản sao cạn có thể là tất cả những gì bạn cần.

Nếu bạn viết cùng một mã ví dụ nhưng sao chép mảng với spread, mảng ban đầu sẽ không còn được sửa đổi:

// Create an Array const originalArray = ['one', 'two', 'three']  // Use spread to make a shallow copy const secondArray = [...originalArray]  // Remove the last item of the second Array secondArray.pop()  console.log(originalArray) 

Phần sau sẽ được ghi vào console :

Output
["one", "two", "three"]

Spread cũng được dùng để chuyển đổi một tập hợp hoặc bất kỳ tập hợp nào khác có thể lặp lại thành Mảng.

Tạo một tập hợp mới và thêm một số mục vào đó:

// Create a set const set = new Set()  set.add('octopus') set.add('starfish') set.add('whale') 

Tiếp theo, sử dụng toán tử spread với set và ghi lại kết quả:

// Convert Set to Array const seaCreatures = [...set]  console.log(seaCreatures) 

Điều này sẽ cung cấp những điều sau:

Output
["octopus", "starfish", "whale"]

Điều này cũng có thể hữu ích để tạo một mảng từ một chuỗi:

const string = 'hello'  const stringArray = [...string]  console.log(stringArray) 

Điều này sẽ cung cấp một mảng với mỗi ký tự là một mục trong mảng:

Output
["h", "e", "l", "l", "o"]

Lây lan với các đối tượng

Khi làm việc với các đối tượng, spread được dùng để sao chép và cập nhật các đối tượng.

Ban đầu, Object.assign() được sử dụng để sao chép một đối tượng:

// Create an Object and a copied Object with Object.assign() const originalObject = { enabled: true, darkMode: false } const secondObject = Object.assign({}, originalObject) 

Đối secondObject bây giờ sẽ là một bản sao của đối tượng originalObject .

Điều này được đơn giản hóa với cú pháp lây lan — bạn có thể sao chép nông một đối tượng bằng cách rải đối tượng đó thành một đối tượng mới:

// Create an object and a copied object with spread const originalObject = { enabled: true, darkMode: false } const secondObject = { ...originalObject }  console.log(secondObject) 

Điều này sẽ dẫn đến những điều sau:

Output
{enabled: true, darkMode: false}

Cũng giống như với mảng, điều này sẽ chỉ tạo một bản sao cạn và các đối tượng lồng nhau sẽ vẫn được chuyển qua tham chiếu.

Việc thêm hoặc sửa đổi các thuộc tính trên một đối tượng hiện có theo kiểu bất biến được đơn giản hóa với spread. Trong ví dụ này, thuộc tính isLoggedIn được thêm vào đối tượng user :

const user = {   id: 3,   name: 'Ron', }  const updatedUser = { ...user, isLoggedIn: true }  console.log(updatedUser) 

Nó sẽ xuất ra như sau:

Output
{id: 3, name: "Ron", isLoggedIn: true}

Một điều quan trọng cần lưu ý khi cập nhật các đối tượng qua spread là bất kỳ đối tượng lồng nhau nào cũng sẽ phải được spread. Ví dụ: giả sử rằng trong đối tượng user có một đối tượng organization lồng nhau:

const user = {   id: 3,   name: 'Ron',   organization: {     name: 'Parks & Recreation',     city: 'Pawnee',   }, } 

Nếu bạn cố gắng thêm một mục mới vào organization , nó sẽ overrides lên các trường hiện có:

const updatedUser = { ...user, organization: { position: 'Director' } }  console.log(updatedUser) 

Điều này sẽ dẫn đến những điều sau:

Output
id: 3 name: "Ron" organization: {position: "Director"}

Nếu khả năng thay đổi không phải là vấn đề, trường có thể được cập nhật trực tiếp:

user.organization.position = 'Director' 

Nhưng vì ta đang tìm kiếm một giải pháp bất biến, ta có thể trải rộng đối tượng bên trong để giữ lại các thuộc tính hiện có:

const updatedUser = {   ...user,   organization: {     ...user.organization,     position: 'Director',   }, }  console.log(updatedUser) 

Điều này sẽ cung cấp những điều sau:

Output
id: 3 name: "Ron" organization: {name: "Parks & Recreation", city: "Pawnee", position: "Director"}

Trải nghiệm với các cuộc gọi chức năng

Spread cũng được dùng với các đối số trong các lệnh gọi hàm.

Ví dụ, đây là một hàm multiply có ba tham số và nhân chúng:

// Create a function to multiply three items function multiply(a, b, c) {   return a * b * c } 

Thông thường, bạn sẽ chuyển ba giá trị riêng lẻ làm đối số cho lệnh gọi hàm, như sau:

multiply(1, 2, 3) 

Điều này sẽ cung cấp những điều sau:

Output
6

Tuy nhiên, nếu tất cả các giá trị bạn muốn chuyển cho hàm đã tồn tại trong một mảng, thì cú pháp lây lan cho phép bạn sử dụng từng mục trong một mảng làm đối số:

const numbers = [1, 2, 3]  multiply(...numbers) 

Điều này sẽ cho kết quả tương tự:

Output
6

Lưu ý: Không có sự lây lan, điều này có thể được thực hiện bằng cách sử apply() :

multiply.apply(null, [1, 2, 3]) 

Điều này sẽ cho:

Output
6

Đến đây bạn đã thấy cách spread có thể rút ngắn mã của bạn, bạn có thể xem cách sử dụng khác của ... cú pháp: tham số nghỉ.

Tham số còn lại

Tính năng cuối cùng bạn sẽ học trong bài viết này là cú pháp tham số còn lại . Cú pháp xuất hiện giống như spread ( ... ) nhưng có tác dụng ngược lại. Thay vì extract một mảng hoặc đối tượng thành các giá trị riêng lẻ, cú pháp còn lại sẽ tạo một mảng với số lượng đối số không xác định.

Ví dụ trong hàm restTest , nếu ta muốn args là một mảng bao gồm một số lượng đối số không xác định, ta có thể có như sau:

function restTest(...args) {   console.log(args) }  restTest(1, 2, 3, 4, 5, 6) 

Tất cả các đối số được truyền cho hàm restTest hiện có sẵn trong mảng args :

Output
[1, 2, 3, 4, 5, 6]

Cú pháp Rest được dùng làm tham số duy nhất hoặc tham số cuối cùng trong danh sách. Nếu được sử dụng làm tham số duy nhất, nó sẽ thu thập tất cả các đối số, nhưng nếu nó ở cuối danh sách, nó sẽ thu thập mọi đối số còn lại, như được thấy trong ví dụ này:

function restTest(one, two, ...args) {   console.log(one)   console.log(two)   console.log(args) }  restTest(1, 2, 3, 4, 5, 6) 

Thao tác này sẽ lấy riêng hai đối số đầu tiên, sau đó group các đối số còn lại thành một mảng:

Output
1 2 [3, 4, 5, 6]

Trong mã cũ hơn, biến arguments số được dùng để thu thập tất cả các đối số được chuyển qua một hàm:

function testArguments() {   console.log(arguments) }  testArguments('how', 'many', 'arguments') 

Điều này sẽ cho kết quả sau:

Output
1Arguments(3) ["how", "many", "arguments"]

Tuy nhiên, điều này có một vài nhược điểm. Đầu tiên, không thể sử dụng biến arguments với các hàm mũi tên.

const testArguments = () => {   console.log(arguments) }  testArguments('how', 'many', 'arguments') 

Điều này sẽ dẫn đến lỗi:

Output
Uncaught ReferenceError: arguments is not defined

Ngoài ra, các arguments không phải là một mảng đúng và không thể sử dụng các phương thức như mapfilter mà không được chuyển đổi trước thành một mảng. Nó cũng sẽ thu thập tất cả các đối số được truyền thay vì chỉ phần còn lại của các đối số, như đã thấy trong ví dụ restTest(one, two, ...args) .

Rest được dùng khi cấu trúc lại mảng:

const [firstTool, ...rest] = ['hammer', 'screwdriver', 'wrench']  console.log(firstTool) console.log(rest) 

Điều này sẽ cho:

Output
hammer ["screwdriver", "wrench"]

Rest cũng được dùng khi cấu trúc các đối tượng:

const { isLoggedIn, ...rest } = { id: 1, name: 'Ben', isLoggedIn: true }  console.log(isLoggedIn) console.log(rest) 

Đưa ra kết quả sau:

Output
true {id: 1, name: "Ben"}

Theo cách này, cú pháp rest cung cấp các phương pháp hiệu quả để thu thập một lượng mục không xác định.

Kết luận

Trong bài viết này, bạn đã tìm hiểu về các tham số cấu trúc hủy, cú pháp lây lan và phần còn lại. Tóm tắt:

  • Cấu trúc hủy được sử dụng để tạo các biến thể từ các mục mảng hoặc thuộc tính đối tượng.
  • Cú pháp Spread được sử dụng để extract các file lặp lại như mảng, đối tượng và lời gọi hàm.
  • Cú pháp tham số còn lại sẽ tạo một mảng từ một số lượng giá trị không xác định.

Cấu trúc hủy, tham số còn lại và cú pháp lây lan là những tính năng hữu ích trong JavaScript giúp giữ cho mã của bạn ngắn gọn và sạch sẽ.

Nếu bạn muốn xem hành động hủy cấu trúc, hãy xem Cách tùy chỉnh thành phần phản ứng với đạo cụ , sử dụng cú pháp này để hủy cấu trúc dữ liệu và chuyển nó tới các thành phần giao diện user tùy chỉnh. Nếu bạn muốn tìm hiểu thêm về JavaScript, hãy quay lại trang loạt bài Cách viết mã trong JavaScript của ta .


Tags:

Các tin liên quan

Cách gỡ lỗi JavaScript với Google Chrome DevTools và Visual Studio Code
2020-05-08
Thanh tiến trình trang với các biến JavaScript và CSS
2020-04-16
Xem xét API JavaScript của trình quan sát thay đổi kích thước
2020-04-16
Xem xét API control panel JavaScript
2020-04-16
Xem xét Đề xuất Nhà điều hành Đường ống JavaScript
2020-04-16
Cách triển khai các phương thức mảng JavaScript từ Scratch
2020-04-09
Các đống nhị phân và hàng đợi ưu tiên qua JavaScript
2020-04-05
JavaScript bất biến có thể thay đổi
2020-04-02
Hiểu các tham số mặc định trong JavaScript
2020-03-31
Cookie là gì và cách làm việc với chúng bằng JavaScript
2020-03-19