Frontend/JS.info 정리

자료구조와 자료형 - 구조 분해 할당(destructuring assignment)

Creative_Lee 2022. 3. 24. 21:25

1. 구조 분해 할당

개발을 하다 보면 함수에 객체, 배열을 전달해야 할 경우가 있습니다.

객체, 배열에 저장된 데이터 전체가 아닌 일부만 필요한 경우도 생깁니다.

 

이럴 때 객체, 배열을 변수로 분해 할 수 있게 해주는 구조 분해 할당을 사용 할 수 있습니다!

 


2. 배열 분해

 

2-1. 기본 문법

let arr = ['Do hyeon','Lee']

let [firstName, lastName] = arr

console.log(firstName) // Do hyeon
console.log(lastName) // Lee

구조 분해 할당을 이용하면 인덱스로 배열에 접근하지 않아도 됩니다!


2-2. 배열을 리턴한다면 무엇이든지

let [firstName, lastName] = 'Dohyeon Lee'.split(' ')

console.log(firstName) // Dohyeon
console.log(lastName) // Lee

배열을 리턴하는 메서드를 사용해도 좋습니다!


2-3. 쉼표로 요소 거르기

let [firstName, , nickName] = ['Dohyeon','Lee','DoBob']

console.log(firstName) // Dohyeon
console.log(nickName) // DoBob

쉼표를 사용해서 필요하지 않은 배열 요소는 버릴 수 있습니다!


2-4. 우측엔 모든 iterable

let [firstName, lastName, nickName] = 'Dohyeon Lee DoBob'.split(' ')

console.log(firstName) // Dohyeon
console.log(lastName) // Dohyeon
console.log(nickName) // DoBob

let [a, b, c] = new Set(['a' ,'b' ,'c'])

console.log(a)
console.log(b)
console.log(c)

할당연산자의 우측에는 배열뿐만 아니라 모든 iterable(for..of문을 사용 가능한 객체)이 올 수 있습니다.

모든 iterable에 구조 분해 할당을 적용할 수 있습니다!


2-5. 좌측엔 할당 가능한 모든 것

let user = {};
[user.firstName, user.lastName] = ['Dohyeon','Lee']

console.log(user) // {firstName: 'Dohyeon', lastName: 'Lee'}

할당연산자의 좌측에는 할당할 수 있는 모든 것이 올 수 있습니다!

객체의 프로퍼티도 가능합니다. 


2-5. Objext.entries(obj) 메소드와의 조합

let user = {
  name : 'Lee',
  age : 27
};

for (let [key, value] of Object.entries(user)){
  console.log(key,value) 
}

// name Lee 출력
// age 27 출력

Object.entries(obj) 메소드와 구조 분해 할당을 조합해서

객체의 키와 값을 순회해 변수에 분해 할당 할 수 있습니다.


2-6. 변수끼리의 값 교환

let user = 'Lee';
let admin = 'Kim';

[user, admin] = [admin, user]

console.log(user) // kim
console.log(admin) // Lee

두 변수에 저장된 값을 서로 교환할 때에도 구조 분해 할당을 사용할 수 있습니다.


2-7. 나머지를 한 곳에 모으기

let [firstName, lastName, age, ...etc] = ['Dohyeon', 'Lee', 27, '나머지는', '전부', 'etc에', '들어가요']

console.log(firstName) // 'Dohyeon'
console.log(lastName) // 'Lee'
console.log(age)  // 27
console.log(etc)  // ['나머지는', '전부', 'etc에', '들어가요']

배옆 앞쪽의 위치한 값 몇 개만 필요하고 그 이후 이어지는 나머지 값들은 한 곳에 모아 저장하고 싶다면

'...' 을 붙인 매개변수를 하나 추가하여 나머지 요소들을 저장할 수 있습니다!

'...' 을 붙인 변수는 항상 맨뒤에 위치해야 합니다!


2-8. 할당할 값이 없다면 undefined

let [firstName, lastName] = []

console.log(firstName) // undefined
console.log(lastName) // undefined

할당 받을 변수의 개수가 분해하고자 하는 배열의 길이보다 크더라도 에러가 발생하지 않습니다.

할당할 값이 없다면 undefined로 취급되기 때문입니다.


2-9. 기본값 설정

let [firstName = 'Dohyeon', lastName = 'Lee'] = ['Taeoh']

console.log(firstName) // 'Taeoh'
console.log(lastName) // 'Lee'

'=' 을 사용해서 할당할 값이 없을 때 기본으로 할당해 줄 기본값을 설정할 수 있습니다.

 

let [firstName = prompt('이름을 입력하세요'), lastName = prompt('성을 입력하세요')] = ['Dohyeon']

console.log(firstName) // 'Dohyeon'
console.log(lastName) // prompt 입력값

기본값으로 복잡한 표현식, 함수 호출도 설정할 수 있습니다.

할당할 값이 없을 때 평가, 실행됩니다.


3.객체 분해

구조 분해 할당으로 객체도 분해할 수 있습니다.

 

3-1. 기본 문법

let size ={width : 10, length : 20, height : 10,}

let {width, length, height} = size;

console.log(width, length, height) // 10 20 10

할당 연산자 우측에는 분해하고자 하는 객체를 두고, 좌측에는 상응하는 객체 프로퍼티의 패턴을 둡니다.


3-2. 순서는 중요하지 않다

let size ={width : 10, length : 20, height : 10,}

let {height, length, width} = size; // 순서가 바뀌어도 상응하는 변수에 할당 됩니다.

console.log(width, length, height)  // 10 20 10

변수의 순서는 중요하지 않습니다.

순서가 바뀌어도 상응하는 변수에 자동으로 할당 됩니다.


3-3. 원하는 변수에 할당

let size ={ width : 10, length : 20, height : 10 }

let {width : w, length : l, height : h} = size;

console.log(w, l, h)

분해하려는 객체의 프로퍼티와 변수의 연결을 원하는 대로 조정 할 수 있습니다.

':' 은  '분해하려는 객체의 프로퍼티 : 목표 변수' 의 형태로 사용됩니다.

위 예시에서는 width 프로퍼티를 분해하여 w 변수에 할당했습니다.


3-4. 기본값 설정

let size = {width : 30, height : 10 }

let {width : w = 10, length : l = +prompt('length를 입력하세요.'), height : h = 20} = size;

console.log(w, l, h) // 30 prompt입력값 20

배열 분해와 마찬가지로 객체 분해에서도 기본값을 설정할 수 있습니다.

위 예시에서는 length 프로퍼티가 없으므로 l 변수에 prompt 입력값이 할당됩니다.


3-5. 원하는 프로퍼티만

let size = {width : 30, height : 10 }

let {width :  w} = size;

console.log(w)  // 30

분해하려는 객체에서 원하는 프로퍼티만 뽑아 저장할 수 있습니다.


3-6. 나머지 프로퍼티를 한 곳에

let size = {width : 30, length : 20, height : 10}

let {width : w, ...others} = size;

console.log(w)  // 30
console.log(others)  // {length: 20, height: 10}

분해하려는 객체의 프로퍼티 개수가 할당하려는 변수의 개수보다 많다면,
배열 분해에서와 같이 나머지 프로퍼티를 모아 저장할 수 있습니다.


3-7. 기존에 있던 변수에 할당하기

기존에 있던 변수에 분해한 값을 할당할 수도 있는데, 이때는 주의해야할 점이 있습니다.

let size = {width : 30, length : 20, height : 10}

let width, length, height;

{width, length, height} = size //  SyntaxError: Unexpected token `=`

자바스크립트는 표현식 안에 있지 않으면서 코드의 흐름 상에 있는 '{ }' 을 코드 블록으로 인식합니다.

위의 예시에서는 자바스크립트가 { ... }을 코드 블록으로 인식하여 에러가 발생했습니다. 

 

let size = {width : 30, length : 20, height : 10}

let width, length, height;

({width, length, height} = size) // 괄호로 인해 에러가 발생하지 않습니다.

console.log(width, length, height) // 30 20 10

위의 예시와 같이 할당문 전체를 괄호로 감싸면 표현식으로 해석됩니다.


4.중첩 구조 분해

객체나 배열이 다른 객체나 배열을 포함하는 중첩 구조의 경우에도 마찬가지로

조금 더 복잡한 패턴을 사용하면 구조 분해 할당이 가능합니다.

이것을 중첩 구조 분해 라고 부릅니다.

let options = {
  size : {width : 30, length : 20, height : 10},
  items : ["pizza", "icecream"]
}

let {
  size : {width : w, length : l, height : h},
  items : [item1 , item2]
} = options;

console.log(size) // size is not defined
console.log(items) // items is not defined
console.log(w) // 30
console.log(l) // 20
console.log(h) // 10
console.log(item1) // "pizza"
console.log(item2) // "icecream"

위 예시에서 size, items를 위한 변수는 없습니다.

대신 size와 items 안의 정보를 변수에 할당 했습니다.

 

let options = {
  size : {width : 30, length : 20, height : 10},
  items : ["pizza", "icecream"]
}

let {size, items} = options;

console.log(size) //{width: 30, length: 20, height: 10}
console.log(items)  // ["pizza", "icecream"]

그게 싫다면 이렇게 할당해서 따로 사용해도 되겠죠?

 


5. 함수의 매개변수를 스마트하게

let showArticle(title = 'Untitled', width = 100, height = 100, items =[]){
  //...
}

위와 같이 함수를 작성하면, 전달할 인자의 순서를 틀려버리면 문제가 발생할 수 있습니다.

 

showArticle("Iron man", undefined, undefined, ['victory, war'])

또한 함수 사용시 일부의 인자만 전달하고 나머지는 기본값을 사용하고 싶다면,
기본값을 사용할 인자 부분에 undefined를 명시하여 전달해야 합니다.


5-1. 해결법

let options = {
  title : "Iron man",
  items : ['war', 'victory']
}

function showArticle({
  title = 'Untitled',
  width : w = 100,
  height : h = 100, 
  items : [item1, item2] = ['no item' ,'no item']
  }){
  console.log(title, w, h, item1, item2)
}

showArticle(options) // Iron man 100 100 war victory
showArticle() // error!!

이런 지저분한 행동을 방지하려면 구조 분해 할당을 사용하면 됩니다!!

전달할 인자를 객체에 모두모아 함수에 전달하면, 함수가 전달받은 객체를 분해하고 매개변수에 할당합니다.

순서에 상관없이 매개변수와 일치하는 프로퍼티는 분해한 뒤 할당하고,

전달 되지 않은 값은 자연스럽게 기본값으로 할당합니다.

 

함수 매개변수를 구조 분해 하려면 항상 객체 형태의 인자가 전달되어야 합니다.

아무것도 전달하지 않는다면 에러가 발생합니다.


5-2. 파라미터의 기본값으로 빈 객체를! 

let options = {
  title : "Iron man",
  items : ['war', 'victory']
}

function showArticle({
  title = 'Untitled',
  width : w = 100,
  height : h = 100, 
  items : [item1, item2] = ['no item','no item']
  } = {}){	// 이 부분에 = {} 를 써주었습니다. 
  console.log(title, w, h, item1, item2)
}

showArticle()  // Untitled 100 100 no item no item

모든 매개변수에 대하여 설정된 기본값을 사용하고 싶다면,

빈 객체 '{ }' 를 전달해주어야 하는데 명시적으로 전달하는 것에는 실수가 생길수 도 있으니

아예 빈 객체 '{ }' 를 인수 전체의 기본값으로 설정해주면 됩니다.

 

위 예시처럼 설정해두면 아무 인자 없이 함수를 실행하여도 잘 동작합니다.

 

 

 

기본이 중요하다.