JavaScript >> Javascript 文檔 >  >> JavaScript

了解解構、休息參數和傳播語法

這篇文章最初是為 DigitalOcean 寫的。

簡介

自 2015 版 ECMAScript 規範以來,JavaScript 語言已經可以使用許多用於處理數組和對象的新功能。您將在本文中學習的一些值得注意的是解構 , 剩餘參數 , 和傳播 句法。這些特性提供了更直接的方式來訪問數組或對象的成員,並且可以更快、更簡潔地處理這些數據結構。

許多其他語言沒有用於解構、剩餘參數和傳播的相應語法,因此這些特性可能對新的 JavaScript 開發人員和來自其他語言的開發人員都有一個學習曲線。在本文中,您將學習如何解構對象和數組,如何使用擴展運算符解包對象和數組,以及如何在函數調用中使用剩餘參數。

解構

解構賦值 是一種語法,允許您將對象屬性或數組項分配為變量。這可以大大減少操作這些結構中的數據所需的代碼行。解構有兩種類型:對象解構和數組解構。

對象解構

對象解構允許您使用對象屬性作為值來創建新變量。

考慮這個例子,一個表示帶有 id 的筆記的對象 , title , 和 date

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

傳統上,如果您想為每個屬性創建一個新變量,則必須單獨分配每個變量,並進行大量重複:

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

使用對象解構,這一切都可以在一行中完成。通過將每個變量括在大括號 {} 中 , JavaScript 將從每個具有相同名稱的屬性中創建新變量:

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

現在,console.log() 新變量:

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

您將獲得原始屬性值作為輸出:

1
My first note
01/01/1970

對象解構的默認賦值會創建與對象屬性同名的新變量。如果您不希望新變量與屬性名稱相同,您還可以選擇使用冒號重命名新變量 (: ) 來決定一個新名稱,如 noteId 所示 如下:

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

記錄新變量 noteId 到控制台:

console.log(noteId)

您將收到以下輸出:

1

您還可以解構嵌套對象值。例如,更新 note 對像有一個嵌套的 author 對象:

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

現在你可以解構 note ,然後再次解構以從 author 創建變量 屬性:

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

接下來,記錄新變量 firstNamelastName 使用模板文字:

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

這將給出以下輸出:

Sherlock Holmes

請注意,在此示例中,儘管您可以訪問 author 的內容 對象,author 對象本身不可訪問。為了訪問對象及其嵌套值,您必須單獨聲明它們:

// Access object and nested values
const {
  author,
  author: {firstName, lastName},
} = note

console.log(author)

此代碼將輸出 author 對象:

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

由於這個屬性,解構對像不僅有助於減少您必須編寫的代碼量;它還允許您定位對您關心的屬性的訪問。

最後,解構可用於訪問原始值的對象屬性。例如,String 是字符串的全局對象,具有 length 屬性:

const {length} = 'A string'

這將找到字符串的固有長度屬性並將其設置為等於 length 多變的。記錄 length 看看這是否有效:

console.log(length)

你會得到以下輸出:

8

字符串 A string 在此處被隱式轉換為對像以檢索 length 屬性。

數組解構

數組解構允許您使用數組項作為值來創建新變量。考慮這個例子,一個包含日期各個部分的數組:

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

JavaScript 中的數組保證保持它們的順序,所以在這種情況下,第一個索引總是一年,第二個索引是月份,依此類推。知道了這一點,您就可以從數組中的項目創建變量:

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

但是手動執行此操作會佔用代碼中的大量空間。使用數組解構,您可以按順序從數組中解包值並將它們分配給自己的變量,如下所示:

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

現在記錄新變量:

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

你會得到以下輸出:

1970
12
01

可以通過在逗號之間將解構語法留空來跳過值:

// Skip the second item in the array
const [year, , day] = date

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

運行它會給出 year 的值 和 day

1970
01

嵌套數組也可以被解構。首先,創建一個嵌套數組:

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

然後解構該數組並記錄新變量:

// Destructure nested items
const [one, two, [three, four], five] = nestedArray

console.log(one, two, three, four, five)

您將收到以下輸出:

1 2 3 4 5

解構語法可用於解構函數中的參數。為了測試這一點,您將解構 keysvalues 超出 Object.entries() .

首先,聲明 note 對象:

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

給定這個對象,你可以通過解構參數來列出鍵值對,因為它們被傳遞給 forEach() 方法:

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

或者你可以使用 for 來完成同樣的事情 循環:

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

無論哪種方式,您都會收到以下信息:

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

對象解構和數組解構可以組合在一個解構賦值中。默認參數也可以與解構一起使用,如本例所示,將默認日期設置為 new Date() .

首先,聲明 note 對象:

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

然後解構對象,同時還設置一個新的date 默認為 new Date() 的變量 :

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

console.log(date)

console.log(date) 然後會給出類似於以下的輸出:

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

如本節所示,解構賦值語法為 JavaScript 增加了很多靈活性,並允許您編寫更簡潔的代碼。在下一節中,您將看到如何使用擴展語法將數據結構擴展為它們的組成數據條目。

傳播

傳播 語法(... ) 是 JavaScript 的另一個有用的補充,用於處理數組、對象和函數調用。 Spread 允許對對象和可迭代對象(如數組)進行解包或擴展,可用於製作數據結構的淺拷貝,以增加數據操作的便利性。

用數組傳播

Spread 可以使用數組簡化常見任務。例如,假設您有兩個數組並希望將它們組合起來:

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

最初你會使用 concat() 連接兩個數組:

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

現在你也可以使用 spread 將數組解包成一個新數組:

// Unpack the tools Array into the allTools Array
const allTools = [...tools, ...otherTools]

console.log(allTools)

運行它會得到以下結果:

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

這對於不變性特別有用。例如,您可能正在使用具有 users 的應用程序 存儲在對像數組中:

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

你可以使用 push 修改現有數組並添加一個新用戶,這將是可變選項:

// A new user to be added
const newUser = {id: 3, name: 'Ron'}

users.push(newUser)

但這會改變 user 數組,我們可能想要保留它。

Spread 允許您從現有數組創建一個新數組並在末尾添加一個新項:

const updatedUsers = [...users, newUser]

console.log(users)
console.log(updatedUsers)

現在是新數組 updatedUsers ,有新用戶,但原來的users 數組保持不變:

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

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

創建數據副本而不是更改現有數據有助於防止意外更改。在 JavaScript 中,當您創建一個對像或數組並將其分配給另一個變量時,您實際上並不是在創建一個新對象,而是在傳遞一個引用。

以這個例子為例,其中創建了一個數組並將其分配給另一個變量:

// Create an Array
const originalArray = ['one', 'two', 'three']

// Assign Array to another variable
const secondArray = originalArray

去掉第二個Array的最後一項會修改第一個:

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

console.log(originalArray)

這將給出輸出:

["one", "two"]

Spread 允許您製作數組或對象的淺拷貝,這意味著任何頂級屬性都將被克隆,但嵌套對象仍將通過引用傳遞。對於簡單的數組或對象,可能只需要一個淺拷貝。

如果寫同樣的示例代碼,但是用spread複製數組,原來的Array就不會再修改了:

// 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)

以下將記錄到控制台:

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

Spread 還可用於將集合或任何其他可迭代對象轉換為數組。

創建一個新集合併向其中添加一些條目:

// Create a set
const set = new Set()

set.add('octopus')
set.add('starfish')
set.add('whale')

接下來,使用帶有 set 的擴展運算符 並記錄結果:

// Convert Set to Array
const seaCreatures = [...set]

console.log(seaCreatures)

這將給出以下內容:

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

這對於從字符串創建數組也很有用:

const string = 'hello'

const stringArray = [...string]

console.log(stringArray)

這將給出一個數組,其中每個字符作為數組中的一項:

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

隨對像傳播

在處理對象時,可以使用 spread 來複製和更新對象。

原來,Object.assign() 用於復制對象:

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

secondObject 現在將是 originalObject 的克隆 .

這通過擴展語法得到了簡化——您可以通過將對象擴展為新對象來淺拷貝:

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

console.log(secondObject)

這將導致以下結果:

{enabled: true, darkMode: false}

就像數組一樣,這只會創建一個淺拷貝,嵌套對象仍然會通過引用傳遞。

以不可變的方式在現有對像上添加或修改屬性可以通過擴展簡化。在本例中,isLoggedIn 屬性被添加到 user 對象:

const user = {
  id: 3,
  name: 'Ron',
}

const updatedUser = {...user, isLoggedIn: true}

console.log(updatedUser)

這將輸出以下內容:

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

通過傳播更新對象需要注意的一件重要事情是,任何嵌套對像也必須被傳播。例如,假設在 user 對像有一個嵌套的 organization 對象:

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

如果您嘗試向 organization 添加新項目 ,它會覆蓋現有的字段:

const updatedUser = {...user, organization: {position: 'Director'}}

console.log(updatedUser)

這將導致以下結果:

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

如果可變性不是問題,可以直接更新該字段:

user.organization.position = 'Director'

但是由於我們正在尋求一個不可變的解決方案,我們可以傳播內部對像以保留現有屬性:

const updatedUser = {
  ...user,
  organization: {
    ...user.organization,
    position: 'Director',
  },
}

console.log(updatedUser)

這將給出以下內容:

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

通過函數調用傳播

Spread 也可以與函數調用中的參數一起使用。

例如,這是一個 multiply 接受三個參數並將它們相乘的函數:

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

通常,您會將三個值分別作為參數傳遞給函數調用,如下所示:

multiply(1, 2, 3)

這將給出以下內容:

6

但是,如果您要傳遞給函數的所有值都已存在於數組中,則擴展語法允許您將數組中的每個項目用作參數:

const numbers = [1, 2, 3]

multiply(...numbers)

這將給出相同的結果:

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

這將給出:

6

現在您已經了解了擴展如何縮短您的代碼,您可以看看 ... 的不同用法 語法:剩餘參數。

休息參數

您將在本文中學習的最後一個功能是 rest 參數 句法。語法與spread 相同(... ) 但有相反的效果。其餘語法不會將數組或對象解包為單獨的值,而是創建一個包含不定數量參數的數組。

在函數 restTest 例如,如果我們想要 args 要成為由不定數量的參數組成的數組,我們可以有以下內容:

function restTest(...args) {
  console.log(args)
}

restTest(1, 2, 3, 4, 5, 6)

傳遞給 restTest 的所有參數 args 中現在提供函數 數組:

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

Rest 語法可以用作唯一的參數,也可以用作列表中的最後一個參數。如果用作唯一參數,它將收集所有參數,但如果它位於列表的末尾,它將收集剩餘的所有參數,如下例所示:

function restTest(one, two, ...args) {
  console.log(one)
  console.log(two)
  console.log(args)
}

restTest(1, 2, 3, 4, 5, 6)

這將單獨獲取前兩個參數,然後將其餘參數分組到一個數組中:

1
2
[3, 4, 5, 6]

在舊代碼中,arguments 變量可用於收集傳遞給函數的所有參數:

function testArguments() {
  console.log(arguments)
}

testArguments('how', 'many', 'arguments')

這將給出以下輸出:

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

然而,這有一些缺點。一、arguments 變量不能與箭頭函數一起使用。

const testArguments = () => {
  console.log(arguments)
}

testArguments('how', 'many', 'arguments')

這會產生錯誤:

Uncaught ReferenceError: arguments is not defined

此外,arguments 不是真正的數組,不能使用像 map 這樣的方法 和 filter 無需先轉換為數組。它還將收集所有傳遞的參數,而不僅僅是其餘的參數,如 restTest(one, two, ...args) 中所示 例子。

解構數組時也可以使用 Rest:

const [firstTool, ...rest] = ['hammer', 'screwdriver', 'wrench']

console.log(firstTool)
console.log(rest)

這將給出:

hammer
["screwdriver", "wrench"]

解構對象時也可以使用rest:

const {isLoggedIn, ...rest} = {id: 1, name: 'Ben', isLoggedIn: true}

console.log(isLoggedIn)
console.log(rest)

給出以下輸出:

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

通過這種方式,rest 語法為收集不確定數量的項目提供了有效的方法。

結論

在本文中,您了解了解構、擴展語法和剩餘參數。總結:

  • 解構用於從數組項或對象屬性創建變量。
  • 擴展語法用於解包可迭代對象,例如數組、對象和函數調用。
  • Rest 參數語法將根據不定數量的值創建一個數組。

解構、rest 參數和擴展語法是 JavaScript 中的有用功能,可幫助您保持代碼簡潔明了。

如果您想了解解構的實際效果,請查看如何使用 Props 自定義 React 組件,它使用此語法來解構數據並將其傳遞給自定義前端組件。如果您想了解有關 JavaScript 的更多信息,請返回我們的如何在 JavaScript 中編碼系列頁面。


Tutorial JavaScript 教程
  1. 使用 FireQuery 更改 Google 徽標

  2. React 事件的世界 |第 10 天

  3. 如何使用 Gatsby、React Leaflet 和 GraphCMS 創建旅行遺願清單地圖

  4. async.waterfall 和 async.series 有什麼區別

  5. 如何使用 Svelte 配置 Tailwind?

  6. 使用 App Framework 創建移動 HTML5 應用程序

  7. 第 3/100 天,100 天的代碼

  1. React 反模式第 1 部分

  2. React Router:使用高階組件重定向

  3. 在 VSCode 中使用 Emmet 加速 HTML 代碼

  4. 這是另一個令人興奮的前端挑戰列表

  5. 如何使用 Javascript 對 URL 進行編碼和解碼

  6. 瀏覽器大戰與 JavaScript 的誕生

  7. React 視差滾動網頁設計方案

  1. 在 JavaScript 中處理非常大的數字

  2. Vue.js 和 AWS Lambda:開發生產就緒型應用程序(第 1 部分)

  3. 在 Mongoose 中更新文檔

  4. 介紹對 Nx 的 Expo 支持