티스토리 뷰

반응형

 

구조분해할당 (Destructuring)

구조분해할당

 

 

구조분해 할당은 배열이나 객체에서 특정 값을 쉽게 추출하여 변수에 할당할때 쓰는 문법이다.

 

 

배열 구조분해할당

사용법은 아래와 같고, 배열에 할당된 순서대로 구조분해할당하여 추출해서 사용할 수 있다.

const numbers = [1, 2, 3]; 

// 기존 방식 
const a = numbers[0]; 
const b = numbers[1]; 

// 구조분해할당 
const [x, y, z] = numbers; 
console.log(x, y, z); // 1 2 3

 

 

만약 특정 인덱스의 값을 넘기고 싶다면 해당하는 부분을 비워두고 콤마(,)로 넘어가면된다.

const numbers = [1, 2, 3, 4, 5]; 

// 두 번째 값을 비워두면 건너뛰기가 가능하다
const [첫번째, , 세번째] = numbers; 
console.log(첫번째, 세번째); // 1 3

 

 

값의 할당을 넘기는 것도 가능하고 나머지 매개변수(rest)처럼 나머지 변수로 처리하는것도 가능하다

const [첫번째, 두번째, ...나머지] = [10, 20, 30, 40, 50]; 
console.log(첫번째, 두번째); // 10 20 
console.log(나머지); // [30, 40, 50]

 

 

만약 배열의 값이 없는 경우(undefined) 기본 값을 설정할 수 있다.

구조분해할당의 변수 영역에서 '='를 통해 설정해준다. 

const [첫번째 = 10, 두번째 = 20] = [5]; 
console.log(첫번째, 두번째); // 5, 20

 

'첫번째'는 5라는 값이 할당되어있으므로 기본값이 아닌 할당된 '5'가 출력되고,

'두번째'는 해당하는 인덱스에 값이 없으므로 (undefined) 기본값으로 할당해준 기본값 '20'이 출력된다.

 

 

객체 구조분해할당

객체도 배열과 유사하게 사용할 수 있다.

배열과 다른점이 있다면 배열의 변수명은 할당되는 값과 연관이 없이 사용자가 원하는대로 자유롭게 등록할 수 있지만,

객체의 구조분해할당 변수명은 할당되는 값의 키 값과 동일하게 사용해야한다.

const person = { name: "Alice", age: 25 }; 

// 기존 방식 
const name1 = person.name; 
const age1 = person.age; 

// 구조분해할당 
const { name, age } = person; 
console.log(name, age); // Alice 25

 

만약...

다른 변수명으로 할당하고 싶다면 ':'를 통해 설정해줘야한다.

const person = { name: "Alice", age: 25 }; 
const { name: userName, age: userAge } = person; 
console.log(userName, userAge); // Alice 25

 

기본 값도 배열과 마찬가지로 설정할 수 있다.

구조분해할당 변수 영역에서 '='를 통해 할당해준다.

이때도 마찬가지로 할당되는 값이 없을 때에만 기본값을 사용하게된다.

const person = { name: "Alice" }; 
const { name, age = 30 } = person; 
console.log(name, age); // Alice 30 (age 기본값 사용)

 

중첩된 객체도 중첩 구조분해할당이 가능하다.

const person = { name: "Alice", address: { city: "Seoul", zip: "12345" } }; 

// 중첩 구조 분해 
const { address: { city, zip } } = person; 
console.log(city, zip); // Seoul 12345

 

 

함수 구조분해할당

함수의 매개변수에서도 구조분해할당을 사용할 수 있다.

함수는 대체 어디서? 라고 생각하겠지만 1. 매개변수, 2.리턴값 에서 구조분해 할당을 사용할 수 있다.

매개변수를 아래와 같이 구조분해할당하여 사용할 수 있다.

// 기존 방식
function displayUser(user) { 
    console.log(`이름: ${user.name}, 나이: ${user.age}`); 
} 

// 구조분해할당
function displayUser({ name, age }) { 
    console.log(`이름: ${name}, 나이: ${age}`); 
} 

const user = { name: "Bob", age: 28 }; 
displayUser(user); // 이름: Bob, 나이: 28

 

또한, 객체와 마찬가지로 기본값 설정이 가능하다.

이것 역시 동일하게 할당된 값이 있으면 기본값을 사용하지 않는다.

function greet({ name = "Guest" }) { 
    console.log(`Hello, ${name}!`); 
} 

greet({ name: "Tom" }); // Hello, Tom! 
greet({}); // Hello, Guest! (기본값 사용)

 

리턴하는 값(배열, 객체)에서 구조분해할당은 아래와 같이 사용된다. 

// 예시 1
function getCoordinates() { 
    return [10, 20]; 
} 
const [x, y] = getCoordinates(); 
console.log(x, y); // 10 20

// 예시 2
function getCoordinates() { 
    return { x: 10, y: 20 }; 
} 
const {x, y} = getCoordinates(); 
console.log(x, y); // 10 20

 

 

또 어디서 사용될까? 했을때,

React에서 많이 사용되는 useState 훅이 구조분해할당을 사용한 사례이다.

useState훅은 반환값이 [현재 상태, 상태 변경 함수]인데, 이때 배열 구조분해할당을 사용해 count와 setCount로 분리하여 사용한다.

const [count, setCount] = useState(0);

 

 

 

자 쭉 공부하고 내려와서 궁금한 점이 있었다.

 

Q. 배열 구조분해할당 시, 건너뛰기할 수 있는데 이때 비워진 곳은 동작이 어떻게 되는걸까?

const numbers = [1, 2, 3, 4, 5]; 

// 두 번째 값을 비워두면 건너뛰기가 가능하다
const [첫번째, , 세번째] = numbers; 
console.log(첫번째, 세번째); // 1 3

 

A. 건너뛰기할때에는 아무런 변수도 생성되지 않고, 메모리에 저장되지도 않는다. (아예 무시하는 개념)

구조분해 할당에서 비워진 변수를 대할때, 자바스크립트는 아래와 같이 동작한다.

  1. 배열의 요소를 왼쪽 변수부터 차례로 할당하려고 한다.
  2. 변수의 위치에 해당하는 배열의 인덱스를 확인한다.
  3. 두가지 선택사항
    1. 변수가 존재하면? 해당하는 배열의 인덱스의 값을 변수에 할당한다.
    2. 변수가 존재하지 않는다면? 해당 인덱스는 무시된다. 

 

 

Q. 나머지 변수를 할당했을때, 얕은 복사아닌가? 객체라면 여전히 참조되겠지?

const [첫번째, 두번째, ...나머지] = [10, 20, 30, 40, 50]; 
console.log(첫번째, 두번째); // 10 20 
console.log(나머지); // [30, 40, 50]

 

A. '...나머지'로 생성한 경우 새로운 배열로 반환하는데 이것은 얕은 복사(Shallow Copy)이다.

그러므로 배열 내 객체가 포함되어있다면 원본 객체를 참조하게된다.

const 유저들 = [ 
    { name: "Alice", age: 25 }, 
    { name: "Bob", age: 30 }, 
    { name: "Charlie", age: 35 } 
]; 

const [첫번째유저, ...나머지유저] = users; 
console.log(나머지유저); // [ { name: "Bob", age: 30 }, { name: "Charlie", age: 35 } ] 

// 나머지유저 내부 객체 변경 (Bob의 age를 99로 변경) 
나머지유저[0].age = 99;  

// 원본 객체 출력
console.log(유저들); // [ { name: "Alice", age: 25 }, { name: "Bob", age: 99 }, { name: "Charlie", age: 35 } ] 

// 변경한 나머지유저 객체 출력
console.log(나머지유저); // [ { name: "Bob", age: 99 }, { name: "Charlie", age: 35 } ]

 

위 코드를 봤을때..

'나머지유저' 객체를 변경했는데, 해당 객체가 원본 '유저들' 객체를 참조하고 있기때문에 둘다 변경된 것을 확인할 수 있다.

원시값이 아닌 객체는 얕은 복사를 했을 경우에 같은 메모리 주소를 공유하고 있기때문에 객체 내부 속성을 변경하면 원본 배열의 객체에도 영향이 있다. 

때문에 이런 경우 추후 객체의 수정이 있을 가능성을 염두해둔다면 깊은 복사(Deep Copy)를 하는것이 안전하다.

- ex: StructuredClone(), Lodash DeepCopy(), JSON.parse(JSON.stringify()) 등..

 

 

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함