[JS] 모던 자바스크립트 Deep Dive 36장

신지·2024년 5월 26일
post-thumbnail

* 모던 자바스크립트 Deep Dive을 토대로 공부한 것을 정리한 내용으로, 모든 인용문은 모던 자바스크립트 Deep Dive의 문구를 인용한 것입니다.

💡 36장. 디스트럭처링 할당

💫 디스트럭처링 할당 (구조 분해 할당)이란?

구조 분해 할당(destructuring assignment)은 구조화된 배열과 같은 이터러블 또는 객체를 비구조화하여 1개 이상의 변수에 개별적으로 할당하는 것을 의미한다.

구조 분해 할당은 배열과 같은 이터러블 또는 객체 리터럴에서 필요한 값만 추출하여 변수에 할당할 때 유용하다.

💫 배열 디스트럭처링 할당

ES6의 배열 구조 분해 할당은 배열의 각 요소를 배열로부터 추출하여 1개 이상의 변수에 할당한다. 이때 배열 구조 분해 할당의 대상(우변)은 이터러블이어야 하며, 할당 기준은 배열의 인덱스다.
-> 순서대로 할당된다.

const arr = [1, 2, 3];

const [one, two, three] = arr;

console.log(one, two, three); // 1 2 3

배열 구조 분해 할당을 위해서는 할당 연산자 왼쪽에 값을 할당받을 변수를 배열 리터럴 형태로 선언한다.

const [x, y] = [1, 2];

// 우변에 이터러블을 할당하지 않으면 에러가 발생한다.
const [x, y]; // SyntaxError: Missing initializer in destructuring declaration
const [a, b] = {}; // TypeError: {} is not iterable

선언과 할당을 분리할 수 있지만, const 키워드로 변수를 선언할 수 없으므로 권장하지 않는다.

let x, y;
[x, y] = [1, 2];

배열 구조 분해 할당의 기준은 배열의 인덱스이므로 순서대로 할당된다. 이때, 변수의 개수와 이터러블의 요소 개수가 반드시 일치할 필요는 없다.

const [a, b] = [1, 2];
console.log(a, b); // 1 2

const [c, d] = [1];
console.log(c, d); // 1 undefined

const [e, f] = [1, 2, 3];
console.log(e, f); // 1 2

const [g, , h] = [1, 2, 3];
console.log(g, h); // 1 3

내가 생각했을 때 이 부분이 구조 분해 할당의 가장 핵심 포인트라고 생각했다. 변수의 개수와 이터러블 요소 개수가 반드시 일치할 필요는 없기 때문에 원하는 요소만 꺼내서 사용할 수 있다는 점이 장점이라고 생각했다.


배열 구조 분해 할당을 위한 변수에 기본값을 설정할 수 있다.

const [a, b, c=3] = [1, 2]'
console.log(a, b, c); // 1 2 3

// 기본값보다 할당된 값이 우선이다.
const [e, f = 10, g = 3] = [1, 2];
console.log(e, g, f,); // 1 2 3

변수에 Rest 요소를 이용할 수 있다. Rest 요소는 파라미터와 마찬가지로 마지막에 위치해야 한다.

const [x, ...y] = [1, 2, 3];
console.log(x, y); // 1 [ 2, 3 ]

💫 객체 디스트럭처링 할당

ES6 의 객체 구조 분해 할당은 객체의 각 프로퍼티를 객체로부터 추출하여 1개 이상의 변수에 할당한다. 이때 할당의 대상(우변)은 객체이어야 하며, 할당 기준은 프로퍼티 키다. 배열과 다르게 순서는 의미가 없으며 변수 이름과 프로퍼티 키가 일치해야 한다.

const user = { firstName: 'Ungmo', lastName: 'Lee' };

const { lastName, firstName } = user;

console.log(firstName, lastName); // Ungmo Lee

객체 구조 분해 할당을 위해서는 할당 연산자 왼쪽에 프로퍼티 값을 할당받을 변수를 선언해야 하며, 변수를 객체 리터럴 형태로 선언한다.

const { lastName, firstName } = { firstName: "Ungmo", lastName: "Lee"};

배열 객체 할당과 마찬가지로 우변에 객체 또는 객체로 평가될 수 있는 표현식을 할당하지 않으면 에러가 발생한다.

const { lastName, firstName };
// SyntaxError: Missing initializer in destructuring declaration

const { lastName, firstName } = null;
// TypeError: Cannot destructure property 'lastName' of 'null' as it is null.

객체 리터럴 형태로 선언한 변수는 프로퍼티 축약 표현을 통해 선언한 것이다.

const { lastName, firstName } = user;
// 위와 아래는 동치다.
const { lastName: lastName, firstName: firstName } = user;

객체의 프로퍼티 키와 다른 변수 이름으로 프로퍼티 값을 할당받으려면 다음과 같이 사용해야 한다.

const user = { firstName: 'Ungmo', lastName: 'Lee' };

// 프로퍼티 키를 기준으로 디스트럭처링 할당이 이루어진다.
// 프로퍼티 키가 lastName인 프로퍼티 값을 ln에 할당하고,
// 프로퍼티 키가 firstName인 프로퍼티 값을 fn에 할당한다.
const { lastName: ln, firstName: fn } = user;

console.log(fn, ln); // Ungmo Lee

변수에 Rest 요소를 이용할 수 있다. Rest 요소는 파라미터와 마찬가지로 마지막에 위치해야 한다.

const { x, ...rest } = { x: 1, y: 2, z: 3 };
console.log(x, rest); // 1 { y: 2, z: 3 }

💫 spread와 rest

🧐 spread

  • 특정 배열 혹은 객체 값을 복제하는 문법이다.
  • 주로 배열을 풀어서 인자로 전달하거나, 각각의 요소로 넣을 때 사용된다.

spread 문법은 객체 혹은 배열을 펼칠 수 있는 문법이다. 예제로 사용법을 알아보자.

const webParts = ['박채연', '최민준', '이예림', '이지민'];
const anotherWebParts = [...webParts, '장정안'];
console.log(webParts);
console.log(anotherWebParts);

🧐 rest

  • 파라미터를 배열의 형태로 받아서 사용할 수 있다.
  • rest 파라미터를 사용하면 함수의 파라미터로 오는 값들을 모아서 하나의 배열로 만들어준다.

rest는 spread와 생김새는 비슷하지만, 역할은 다르다. rest는 객체, 배열, 함수의 파라미터에서 사용할 수 있다.

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

const [one, ...rest] = numbers;

console.log(one);
console.log(rest);

위와 같은 예제로는 뭐가 다르다는 거지? 싶을 수 있어서 더 이해하기 쉬운 예제를 가져왔다. 함수의 파라미터가 몇 개가 될 지 모르는 상황에서 더하기를 해야 한다고 가정하자.

function sum(...rest) {
  return rest.reduce((acc, current) => acc + current, 0);
}

const result = sum(1, 2, 3, 4, 5, 6);
console.log(result); // 21

위처럼 rest 파라미터를 사용하면, 함수에서 받아온 각각의 수를 쉽게 더할 수 있다!

위처럼 spread가 기존의 배열을 펼쳐서 표현한다면, rest는 배열이 아닌 개별 요소들을 하나의 배열로 만들어 주는 정 반대의 역할을 한다!


리뷰

몰랐던 부분과 더 공부해보고 싶은 부분


채현 언니 PR에 정안 오빠가 달아준 리뷰인데... 사실 나는 이때 구조분해할당을 처음 알았다!

공부하면서 든 생각

주제를 정할 때 합세 코드 컨벤션에 구조분해할당을 적극 이용하자는 말이 있었던 게 생각나서 이 기회에 자세히 알아보고자 정했다! 다들 달아주었던 코드 리뷰 덕분인지... 리드 정우 오빠 덕분인지는 모르겠지만 내가 구조 분해 할당을 하고 있는지도 모르고 자연스레 코드에 구조 분해 할당을 적용하였는데, 이번 기회에 자세히 알아볼 수 있어서 좋았다.


사실 예전에 정우 오빠에게 위와 같은 리뷰를 받은 적이 있는데, 이 당시에는 저게 뭐가 문제인지도 몰랐고 리뷰 받은대로 리팩토링하기 급급했다! 하지만 이번 아티클을 통해서 왜 저게 문제였고... 내가 저렇게 말도 안 되는 구조분해할당을 했었다니... 라고 반성하게 되었다.

헉 근데 교안에는 rest 문법을 사용할 수 있다고 적혀있는데, 정우 오빠는 spread 문법을 사용하면 좋다고 적어두었다...!! 둘의 차이를 알면 좋을 것 같아서 내 아티클에도 적어두긴 했지만.... 예림 언니 저번 주차 아티클에도 비슷한 내용이 있던 것 같아서 긁어왔다,,,
예림 언니의 spread 아티클 보러 가기


예전에 구조분해할당과 관련된 코드리뷰를 받았을 때는 props를 명시해주는 게 더 가독성이 좋다고 생각했다... 감자개발학생이라 뭔가 명시해줘야 아~ 내려줬구나~ 라는 생각이 들었어서 그런가...?? 물론 구조분해할당이 구조분해할당인지도 모르고 사용하고 있었지만 지금은 구조분해할당을 안 사용하는 코드를 보면 뭔가 고쳐주고 싶다는 생각이 든다,,, 물론 다른 사람들은 내 코드에 고치고 싶은 게 오백 개쯤 존재하겠지만!!!! 아무튼 여태 구조분해할당을 제대로 모르고서 쓰고 있었는데 이번 기회에 내가 여태 쓰던 게 어떤 건지 알게 되어서 가장 재미있게 쓴 아티클 같다!! 🫶 그래서그런지사족개길어서죄송합니다ㅠㅠ

3개의 댓글

comment-user-thumbnail
2024년 5월 27일

저도 깊게 이해하지 못하고 습관적으로 쓰게 되는 코드들이 있었는데 오늘 신지님 아티클 보면서 많이 반성하고 갑니다,, ㅎㅎ 왜 해당 구조로 코드를 작성하는지, 다른 더 좋은 구조는 없을지 고민하고 공부해야겠다는 생각이 드네요 신지님 아티클은 매번 왜 해당 주제를 선정했는지, 공부 후 어떤 생각들을 하셨는지, 어떻게 적용하고 싶으신지가 잘 보여서 매번 유익하고 좋은 자극을 받고 가는 것 같습니다 ㅎㅎ 이번주도 수고 많으셨습니다!

답글 달기
comment-user-thumbnail
2024년 5월 27일

오! 제 아티클이 등장하다니..!! 홍홍 이와 관련해서 저저번주차 채연이의 spread랑 rest 완전비교 아티클도 추천합니다! 무언가를 명시해줘야지 더 가독성이 좋다고 생각하셨다는 부분 완전 공감하고 갑니다.. 매주차 공부하면서 든 생각을 적어주셔서 신지님의 아티클맥락이 더 잘 읽히는 것 같아서 너무 좋은 거 같아요!! "이거뭐야?" "구조분해할당이야!" 이런 대화를 최근 3주동안 자주 해서.. 아 진짜 구조분해할당 제대로 공부해야겠다 생각하고 있던 참에 정말 유용했습니다! 감사합니다.☺️

답글 달기
comment-user-thumbnail
2024년 5월 27일

ㅋㅋㅋㅋㅋㅋㅋㅋㅋ 아 너무 솔직한 이야기 재밌네요.. 이번 아티클 역대급(?) 인 것 같아요..
저는 구조분해할당 개념을 알았어도 접근하지 못하고 있는 입장이라, 몰랐음에도 쓰고있던 신지님이 오히려 멋지게 보이네요.. ㅎㅎ 진짜 잘한다고 얘기가 나오는 웹파트원 코드 구경가면, 구조분해할당 너무너무 잘 쓰더라구요.. 입틀막 짱마니함!! 저도 그렇게 될 수 있도록 더더더 노력해보겠습니다 ㅎㅎㅎ!!
(마지막으로.. 제 이름 나와서 너무 너무 신나요 사진 찍어둘게요 .. 헷)

답글 달기