iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 15
1
Modern Web

JavaScript基本功修煉系列 第 15

JavaScript基本功修練:Day15 - 解構賦值的概念與應用

  • 分享至 

  • xImage
  •  

解構賦值是ES6新增的寫法,讓我們更快捷去把陣列或物件裏的值賦予給變數,同時也讓程式碼更易閱讀。解構賦值的概念挺直接的,但自己在應用上還是很不熟悉,所以今天就來學習一下解構賦值的概念和應用。

解構賦值的概念

為什麼ES6會新增解構賦值(Destructuring assignment)的寫法呢?因為在這之前,我們可能要用迭代或迴圈的方式去賦值,程式碼就會變長,而且可讀性較低。例如:

let a = 1;
let b = 2;
let c = 3;

const num = [10,20,30]
const myNum = [a,b,c]
for(i=0; i<num.length; i++){
    myNum[i] = num[i]
}
console.log(myNum) //[10,20,30]

所以ES6新增了解構賦值的寫法,那麼它到底是什麼意思呢?看看MDN頭一段的解釋:

The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.

我們可以把這個詞拆開來想:變成「解構」、「賦值」。「解構」在陣列或物件裏的值,「賦值」給變數。過程就像一個鏡子,把右邊的值,映照到左邊的變數去。

舉個簡單例子:

const city = ['Hong Kong', 'Taipei', 'Tokyo', 'Seoul']
const [cityA, cityB, cityC, cityD] = city

console.log(cityA, cityB, cityC, cityD) // Hong Kong Taipei Tokyo Seoul

以上範例可見,右邊city陣列裏面的值,會順序地賦予給左邊的陣列裏的值。用解構賦值的方式,讓我們只用一行程式碼就完成了賦值的動作。

陣列解構賦值

以下是一些陣列解構賦值(Array destructuring)用法例子:

//1.最簡單用法 
const [cityA, cityB] = ['Hong Kong','Taipei'] 
//cityA = Hong Kong, cityB = Taipei

//2.遇上空的變數時,右邊相應的值會被跳過 
[cityA, ,cityC] = ['Tokyo', 'Seoul', 'BangKok'] 
//cityA = Tokyo, cityC = BangKok

//3.左方多於右方,多出來的值會是undefined
[cityA, , , ,cityE] = ['Tokyo','Seoul'] 
//cityA = Tokyo, cityE = undefined 

//4.同時交換變數
let cityA = 'Taipei';
let cityB = 'Hong Kong';

[cityA, cityB] = [cityB, cityA];
//cityA = Hong Kong, cityB = Taipei

//5.把字串解構成一個個字元,賦值到變數
const [a,b,c,d,e] = 'Tokyo'
// a = 'T', b = 'o', c = 'k', d = 'y', e = 'o'

//6. 其餘運算子
const [cityA,...cityB] = ['Seoul','Taipei','Hong Kong','BangKok'];
//city A = 'Seoul', city B = ['Taipei','Hong Kong','BangKok']

//7. 多維陣列
const [a, [b, [c,d] ]] = [1, [2, [[3,4],5] ]];
//a = 1, b = 2, c = [3,4], d = 5

陣列的解構賦值用法很直接,較特別的例子是其餘運算子的例子,其餘運算子會集合所有餘下的值成為陣列。

物件解構賦值

物件的解構賦值(Object destructuring)與陣列是相同,都是用鏡子的概念。差異在於我們會對應物件的屬性去賦值,而非像陣列那樣,對應索引值去順序賦值。例如我們有一個叫user的物件:

//例如我們有一個叫user的物件
const user = {
    name: 'Tom',
    age: 18
}
//解構賦值寫法。把user物件的name和age屬性值,賦予到對應的變數
const {name,age} = user //name = Tom, age = 18

//解構賦值出現之前的寫法
const name = user.name //name = Tom
const age = user.age //age = 18

注意,物件的解構賦值沒有次序之分,只要有變數的名稱與該物件的鍵(key)名稱相同,就會被賦值,如果不相同,該變數就會變成undefined

//如果變數名稱與鍵(key)不相同,該變數就會是undefined
const {y,name} = user // y = undefined, name = Tom

我們當然也可以自訂變數的名稱:

//重新賦予變數名稱為x和y
const {name:x, age:y} = user  
// x = Tom, y = 18

拿取物件的屬性值,賦予到變數裏:

//拿取user屬性的值,賦予到變數裏
const {name:name, age:age} = user
//name = Tom, age = 18

//或者拿取user屬性的值,賦予到自訂名稱的變數(valA,valB)裏
const {name:valA, age:valB} = user
//valA = Tom, valB = 18

其餘運算子的例子:

const {name,age,city,...rest} = {name: 'Tom', age: 18, gender:'male', city: 'Taipei', pet: 'dog'}
//name = Tom
//age = 18
//city = Taipei
//rest = {gender: "male", pet: "dog"}

另外需要注意{}的前面沒有宣告字詞(varletconst),就會被當作區塊(block),而非物件的意思。例如以下的例子我們要加上括號:

//報錯寫法
 {val1,val2} = {val1: 10, val2: 20}; 
 
//正確寫法
({val1,val2} = {val1: 10, val2: 20});
// val1 = 10, val2 = 20

混合陣列和物件

如果有一個陣列包有物件,或者物件包有陣列,我們要拿它來做解構賦值,該怎樣做呢?其實原理是一樣:

const user = {
    name: 'Amy',
    age: 30,
    pet: ['cat','dog','bird','fish']
}

const {name: x, age:y, pet:[val1, ,val3]}  = user 

console.log(x,y,val1,val3) //Amy, 30, cat, bird

陣列包物件:

const user = [
    'Ken',
    {pet: ['cat',['dogA','dogB']]},
    100
]

const [a,b,c] = user
console.log(a) //Ken
console.log(b) //{pet: ['cat',['dogA','dogB']]}
console.log(c) //100  

應用情況

預設變數的值

剛才提及,有些情況下進行解構賦值後,該變數的值會是undefined,例如左方多右方的數值多,多出來的變數會成為undefined。但我們可以在右方預設變數的值來避免這個情況,例如:

let [name = 'Fiona', age = 24] = ['David']
//name = David, age = 24

let {food = 'banana', color = 'yellow'} = {color: 'red'}
//food = banana, color = red

函式應用

greet預設值是'Nice to meet you'。如果傳入函式的物件裏沒有greet屬性,greet就會是'Nice to meet you':

function greet({name, greet = 'Nice to meet you'}){
    console.log(`${greet}, ${name}`)
}

greet( {name:'Katy', greet:'Hi'}) //Hi, Katy
greet( {name:'John'}) //Nice to meet you, John
greet({}) //Nice to meet you, undefined
greet({greet:'Good morning'}) //Good morning, undefined

其餘運算子例子:

function person({name,university,language = 'English'},...skills){
    console.log(`Name: ${name}, University: ${university}, Language ${language}, Skills: ${skills}`)
}

person({name:'Mary',university:true},'JavaScript','Ruby','PHP')
//Name: Mary, University: true, Language English, Skills: JavaScript,Ruby,PHP
person({name:'Tom',university:false,language:'Mandarin'},'C','JavaScript','PHP')
//Name: Tom, University: false, Language Mandarin, Skills: C,JavaScript,PHP

高階函式的例子:
同上面的原理一樣,num預設值是'unknown',如果傳入的物件沒有num屬性,num就會是'unknown'

const list = [{name: 'Eva'},{name: 'Carrie', num:23},{name:'Olivia'}]
list.forEach( ({name, num = 'unknown'}) => console.log(`Hi I'm ${name}. My number is ${num}.`)) 
//Hi I'm Eva. My number is unknown.
//Hi I'm Carrie. My number is 23.
//Hi I'm Olivia. My number is unknown.

参考資料

從ES6開始的JavaScript學習生活 - 解構賦值
鐵人賽:ES6 解構賦值


上一篇
JavaScript基本功修練:Day14 - 陣列高階函數練習之Codewars刷題(II)
下一篇
JavaScript基本功修練:Day16 - 原型的基本概念
系列文
JavaScript基本功修煉31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言