만자의 개발일지

[JavaScript] 비구조화(구조분해) 할당 본문

JavaScript

[JavaScript] 비구조화(구조분해) 할당

박만자 2022. 5. 10. 11:09

ES6가 등장하기 이전에 배열에 있는 요소 혹은 JSON 객체의 프로퍼티를 각각 변수에 담기위해 다음과 같이 일일이 하나하나 변수에 할당해주곤 했습니다.

let users = ['홍길동', '김철수', '박민재']

let user1 = users[0]
let user2 = users[1]
let user3 = users[2]

console.log(user1)
console.log(user2)
console.log(user3)

let user = {
    name: '홍길동',
    age: '20'
}

let name = user.name
let age = user.age

console.log(name)
console.log(age)
홍길동
김철수
박민재
홍길동
20

하지만 이 경우에 배열의 요소가 많아지거나 JSON 객체의 프로퍼티 수가 많아지면 작성하기도 귀찮아지고, 코드의 가독성도 떨어질 뿐더러 유지보수도 힘들어집니다.

이러한 문제를 해결하기위해 ES6부터 비구조화 할당(Destructuring Assignment)이라는 새로운 자바스크립트 표현식이 추가되었습니다.

 

비구조화(구조분해) 할당(Destructuring Assignment)

비구조화 할당이란 배열이나 JSON 객체의 프로퍼티를 해체하여 그 값을 개별 변수에 담을 수 있게 해주는 자바스크립트 표현식 입니다.

 

비구조화 할당 사용법

위 예시 코드를 비구조화 할당을 사용하여 다음과 같이 바꿀 수 있습니다.

let [user1, user2, user3] = ['홍길동', '김철수', '박민재']

console.log(user1)
console.log(user2)
console.log(user3)

let {name, age, gender} = {
    name: '홍길동',
    age: '20',
    gender: '남'
}

console.log(name)
console.log(age)
console.log(gender)
홍길동
김철수
박민재
홍길동
20

비구조화 할당의 기본 구조는 = 을 기준으로 좌항과 우항으로 나뉩니다.

좌항은 변수의 집합으로 이루어져있고, 우항은 할당할 값으로 이루어져있습니다.

배열에서 비구조화 할당을 사용할 경우 좌항의 각 변수에는 같은 인덱스를 가진 우항의 값들이 할당되고,

JSON 객체에서 비구조화 할당을 사용할 경우 우항의 key 값이 좌항의 변수명과 매칭됩니다.

JSON 객체의 key 값 대신 변수명 사용하기

JSON 객체에서 비구조화 할당을 사용하려면 JSON 객체의 key 값을 변수명으로 사용해야 했습니다.

이제 다음과 같은 방법으로 비구조화 할당시 key 값 대신 변수명을 지정해 줄 수 있습니다.

let {name: user_name, age: user_age, gender: user_gender} = { // key: 변수명
    name: '홍길동',
    age: '20',
    gender: '남'
}

console.log(user_name)
console.log(user_age)
console.log(user_gender)
홍길동
20
남

 

또한 key 값이 변수명으로 사용이 불가능한 문자열로 되어있는 경우 다음과 같은 방식으로 비구조화 할당을 사용할 수 있습니다.

let {['user name']: user_name, ['user-age']: user_age, ['user~gender']: user_gender} = {
    'user name': '홍길동',
    'user-age' : 20,
    'user~gender': '남'
}

console.log(user_name)
console.log(user_age)
console.log(user_gender)
홍길동
20
남

중첩된 JSON 객체에서 값 꺼내오기

비구조화 할당에서 중첩된 JSON 객체에서 원하는 값을 꺼내오고 싶은 경우, 다음과 같이 중괄호를 사용하여 원하는 값을 꺼내올 수 있습니다.

const user = {
    name: '홍길동',
    age: 20,
    gender: '남',
    address: {
        city: {
            cityName: 'Seoul',
            ward: {
                wardName: 'Gangnam'
            }
        }
    }
}

const {name, age, gender, address : {
    city: { ward: {
        wardName
    }, cityName }
}} = user

console.log(name)
console.log(age)
console.log(gender)
console.log(cityName)
console.log(wardName)
홍길동
20
남
Seoul
Gangnam

 

또 다른 방법으로 ES6object-shorthand 문법을 사용하여 중첩된 JSON 객체에서 원하는 값을 꺼내올 수 있습니다.

object-shorthand 문법은 객체의 프로퍼티와 변수명이 일치하는 경우 객체를 반환하는데 있어서 불필요한 반복을 없애주는 문법입니다.

const user = {
    name: '홍길동',
    age: 20,
    gender: '남',
    address: {
        city: {
            cityName: 'Seoul',
            ward: {
                wardName: 'Gangnam'
            }
        }
    }
}

const {name, age, gender} = user
const {cityName} = user.address.city
const {wardName} = user.address.city.ward

const extracted = {
    name,
    age,
    gender,
    cityName,
    wardName
}
/*
object-shorthand 문법을 사용하지 않은 경우
const extracted = {
    name: name,
    age: age,
    gender: gender,
    cityName: cityName,
    wardName: wardName
}
*/

console.log(extracted)
{
  name: '홍길동',
  age: 20,
  gender: '남',
  cityName: 'Seoul',
  wardName: 'Gangnam'
}

기본값 할당하기

비구조화 할당을 사용할 때 범위를 벗어나는 값을 할당하려 하면 undefined를 반환하게 됩니다.

이경우에 = 연산자를 이용해 기본값을 지정해줄 수 있습니다.

const user = {
    name: '홍길동',
    age: 20
}
const {name, age, gender = '남'} = user

console.log(name)
console.log(age)
console.log(gender)
홍길동
20
남

함수의 파라미터에서의 사용

함수의 인자값으로 JSON 객체를 전달할 때 비구조화 할당을 사용하여 프로퍼티를 쉽게 받아올 수 있고, 보다 가독성 있는 코드를 작성할 수 있습니다.이 경우 API 응답 값을 처리할 때 유용하게 사용할 수 있습니다. 

const user = {
    name: '홍길동',
    age: 20,
    gender: '남'
}

function printUserInfo({name, age, gender}) {
    console.log(name)
    console.log(age)
    console.log(gender)
}

printUserInfo(user)
홍길동
20
남

 

또한 map 이나 forEach 같은 배열 객체의 함수에서도 비구조화 할당을 사용할 수 있습니다.

const users = [
    {name: '홍길동', age: 20, gender: '남'},
    {name: '김철수', age: 30, gender: '남'},
    {name: '박민재', age: 19, gender: '남'}
]

users.forEach(({name, age, gender}, index) => {
    console.log(index, name, age, gender)
})

users.map(({name, age, gender}) => {
    console.log(name, age, gender)
})
0 홍길동 20 남
1 김철수 30 남
2 박민재 19 남
홍길동 20 남
김철수 30 남
박민재 19 남

for of 문

for of 문에서도 다음과 같이 비구조화 할당을 사용할 수 있습니다.

const users = [
    {name: '홍길동', age: 20, gender: '남'},
    {name: '김철수', age: 30, gender: '남'},
    {name: '박민재', age: 19, gender: '남'}
]

for(let {name, age, gender} of users) {
    console.log(name, age ,gender)
}
홍길동 20 남
김철수 30 남
박민재 19 남

 

잔여 연산자(Rest Operator)

비구조화 할당에서는 잔여 연산자( . . . ) 를 사용할 수 있는데, 잔여 연산자를 사용함으로써 좌항에 할당되지 않은 우항의 나머지 값들을 할당할 수 있습니다.

다만 잔여 연산자를 사용할 때에는 항상 가장 마지막에 위치해야 하며 잔여 연산자는 별도의 변수명을 지정해줄 수 없습니다.

let [user1, ...users] = ['홍길동', '김철수', '박민재']

console.log(user1)
console.log(users)

let {name, ...props} = {
    name: '홍길동',
    age: '20',
    gender: '남'
}

console.log(name)
console.log(props)
홍길동
[ '김철수', '박민재' ]
홍길동
{ age: '20', gender: '남' }

 

전개 연산자(Spread Operator)

전개 연산자잔여 연산자와 같은 점 3개 연산자( . . . )입니다. 하지만 잔여 연산자는 비구조화 할당문에서 사용되고 그 외에 비구조화 할당문이 아닌 곳에서 사용되는 점 3개 연산자전개 연산자라 합니다.

전개 연산자는 말 그대로 객체의 속성을 모두 전개해 새로운 객체로 만들어 줍니다.

값 전체 복사

기존 배열 혹은 객체를 보존해야 할 때 전개 연산자를 이용해 배열 혹은 객체를 손쉽게 복사할 수 있습니다.

복사된 객체는 원본과 다른 메모리 주소를 가지기 때문에 복사된 객체를 수정해도 원본 객체에 영향을 주지 않습니다.

const arr = [1, 2, 3];
const copy1 = [...arr];

const user = {
    name: '홍길동',
    age: 20,
    gender: '남'
}
const copy2 = {...user}

console.log(copy1)
console.log(copy2)
[ 1, 2, 3 ]
{ name: '홍길동', age: 20, gender: '남' }

새로운 값 할당

전개 연산자를 이용해 값을 복사함과 동시에 새로운 값을 할당할 수 있습니다.

const arr = [1, 2, 3];
const copy1 = [...arr, 4];

const user = {
    name: '홍길동',
    age: 20,
    gender: '남'
}
const copy2 = {
    ...user,
    age: 25
}

console.log(copy1)
console.log(copy2)
[ 1, 2, 3, 4 ]
{ name: '홍길동', age: 25, gender: '남' }

 

참고

Comments