Modern Javascript 구조 분해 할당

[Modern Javascript] 구조 분해 할당


본 내용은 모던 자바스크립트 구조 분해 할당을 보고 공부, 정리한 내용입니다.

많은 데이터를 효율적으로 관리하기 위해서 객체, 혹은 배열과 같은 자료구조를 사용한다. key-value 형태로 관리하고 싶다면 객체, 데이터를 순서를 매겨 관리하고 싶다면 배열을 사용한다.
이렇게 단체로 데이터를 관리하다가 그 중 일부만 추출해야 할 필요가 있을 땐 어떻게 해야 할까? 해당 자료구조를 순회하며 필요한 요소만 옮겨 담는 방법을 사용해도 되지만, 이를 더 간단하게 하기 위해 존재하는 문법이 바로 구조 분해 할당이다. 이번 장에서는 구조 분해 할당 문법에 대해 공부해보자.


배열 분해하기

구조 분해 할당 문법은 아래와 같이 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
// 이름과 성을 요소로 가진 배열
let arr = ["Bora", "Lee"]

// 구조 분해 할당을 이용해
// firstName엔 arr[0]을
// surname엔 arr[1]을 할당하였습니다.
let [firstName, surname] = arr;

alert(firstName); // Bora
alert(surname);  // Lee

배열의 구조 분해 할당 특징, 활용

  • 구조 분해 할당 우변에는 이터러블 객체 무엇이든 올 수 있다.
    구조 분해 할당 좌변에는 어떤 변수든 올 수 있다. 즉, 객체의 속성 또한 올 수 있다.
    1
    2
    3
    4
    5
    6
    7
    8
      // 우변
      let [a, b, c] = "abc"; // ["a", "b", "c"]
      let [one, two, three] = new Set([1, 2, 3]);
    
      // 좌변
      let user = {};
      [user.name, user.surname] = "Bora Lee".split(' ');
      alert(user.name); // Bora
    


  • 구조 분해 할당 시 우변에 사용된 이터러블 객체는 변형되지 않는다.
    1
    2
      // 이 연산 이후에도 arr은 본 형태 그대로를 유지한다.
      let [firstName, surname] = arr;
    


  • Object.entries()와 함께 사용하면 객체의 key, value를 다른 변수에 담아 순회할 수 있다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      const obj = {
          name: "nam",
          age: 25,
      }
    
      for([key, value] of Object.entries(obj)) {
          console.log(key, value);
      }
    
      // 출력 결과
      name nam
      age 25
    


  • 쉼표를 사용하여 필요한 변수만 사용할 수 있다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
      const obj = {
          name: "nam",
          age: 25,
          addresss: "서울시 중랑구",
          hobby: "코딩",
      }
    
      let [name, , , hobby] = Object.values(obj);
    
      console.log(name, hobby); // nam 코딩
    


  • 구조 분해 할당 문법을 이용하여 두 변수의 값을 손쉽게 바꿀 수 있다.
    1
    2
    3
    4
    5
    6
      let myName = "nam";
      let yourName = "choi";
    
      [yourName, myName] = [myName, yourName];
    
      console.log(myName, yourName); // choi nam
    


  • … 을 이용하여 나머지 값을 저장할 수 있다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
      let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
    
      alert(name1); // Julius
      alert(name2); // Caesar
    
      // `rest`는 배열입니다.
      alert(rest[0]); // Consul
      alert(rest[1]); // of the Roman Republic
      alert(rest.length); // 2
    


기본값

좌변에 선언한 변수에 할당할 값이 없을 땐 기본적으로 “undefined” 가 할당된다.
이 때 기본값을 설정해주면, 할당할 내용이 없을 때 기본값이 해당 변수에 할당된다.

1
2
3
4
5
// 기본값
let [name = "Guest", surname = "Anonymous"] = ["Julius"];

alert(name);    // Julius (배열에서 받아온 값)
alert(surname); // Anonymous (기본값)


기본값은 복잡한 표현식이나 함수 호출도 될 수 있다.
기본값으로 함수 호출을 사용할 경우, 할당할 속성이 존재하지 않을 때만 호출된다.
아래 예시의 경우 surname 변수에는 할당할 값이 있으므로 prompt문이 실행되지 않는다.

1
2
3
4
5
// name의 prompt만 실행됨
let [surname = prompt('성을 입력하세요.'), name = prompt('이름을 입력하세요.')] = [""];

alert(surname); // 김 (배열에서 받아온 값)
alert(name);    // prompt에서 받아온 값

객체 분해하기

배열을 구조 분해 할당할 때는 대괄호를 사용했지만, 객체를 구조 분해 할당할 때는 중괄호를 사용한다.
좌변의 변수명과 동일한 우변 객체의 속성이 있다면 해당 변수로 값이 할당된다.

1
2
3
4
5
6
7
8
9
10
11
let options = {
  title: "Menu",
  width: 100,
  height: 200
};

let {title, width, height} = options;

alert(title);  // Menu
alert(width);  // 100
alert(height); // 200


위 예시에서 options의 속성 순서가 달라도 동작은 동일하다.

1
2
3
4
5
6
7
8
9
10
11
let options = {
	height: 200,
  title: "Menu",
  width: 100,
};

let {title, width, height} = options;

alert(title);  // Menu
alert(width);  // 100
alert(height); // 200


객체를 구조 분해 할당할 땐 좌변에 조금 더 복잡한 표현식을 사용할 수 있다.
아래 예시는 우변 객체의 width 속성 value을 w 변수에, height 속성 value를 h 변수에 할당한다.
즉, “분해하려는 객체의 속성”: “변수명” 과 같이 표현할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let options = {
  title: "Menu",
  width: 100,
  height: 200
};

// { 객체 프로퍼티: 목표 변수 }
let {width: w, height: h, title} = options;

// width -> w
// height -> h
// title -> title

alert(title);  // Menu
alert(w);      // 100
alert(h);      // 200


객체 구조 분해 할당 시에도 기본값 설정이 가능하다. 기본값 문법은 배열 분해할 때와 동일하게 “=” 을 사용한다.
마찬가지로 복잡한 표현식이나 함수도 기본값이 될 수 있으며, 기본값 함수는 할당할 변수가 없을 시에만 호출된다.
콜론과 기본값 문법은 동시에 사용 가능하다.

1
2
3
4
5
6
7
8
9
10
11
let options = {
	title: "Menu",
	// width: 100,
	height: 200,
};

let {title = prompt("제목을 입력하세요"), width: w = 300, height: h = 300} = options;

console.log(title); // 할당할 속성이 있으므로 기본값 함수가 실행되지 않음
console.log(w);     // width 속성이 없으므로 기본값 300
console.log(h);     // height 속성이 있으므로 200


객체 분해 할당 또한 나머지 패턴 (…) 을 사용할 수 있다. 배열에서는 나머지 변수가 배열이었던 것 처럼, 객체 분해 시 나머지 변수는 객체가 된다.
나머지 패턴은 IE 등의 구식 브라우저에서는 지원하지 않는다는 점을 알아두자.

1
2
3
4
5
6
7
8
9
10
11
12
13
let options = {
  title: "Menu",
  height: 200,
  width: 100
};

// title = 이름이 title인 프로퍼티
// rest = 나머지 프로퍼티들
let {title, ...rest} = options;

// title엔 "Menu", rest엔 {height: 200, width: 100}이 할당됩니다.
alert(rest.height);  // 200
alert(rest.width);   // 100


  • 주의
    지금까지는 객체에 구조 분해 할당 문법을 적용할 때 변수를 새로 선언함과 동시에 할당하여 “let” 선언자를 같이 사용했었다.
    기존에 존재하는 변수에 구조 분해 할당을 사용하면 어떻게 될까?
    1
    2
    3
    4
      let title, width, height;
    
      // error 발생
      {title, width, height} = {title: "Menu", width: 200, height: 100};
    

    위 예시를 실행해보면 에러가 발생한다.
    자바스크립트에서 중괄호는 기본적으로 코드 block을 표현하는 용도이므로, 자바스크립트 엔진이 위 예시의 좌변 중괄호를 변수 할당이 아닌 코드 블럭으로 인식해서 발생하는 에러이다.
    이러한 에러를 방지하려면 구조 분해 할당식을 소괄호로 감싸주면 된다.

    1
    2
    3
    4
      let title, width, height;
    
      // 정상적으로 동작
      ({title, width, height} = {title: "Menu", width: 200, height: 100});
    

중첩 구조 분해

배열 혹은 객체 내부에 또 다른 배열, 객체가 value로 존재하는 경우, 이를 중첩 구조라고 부른다.
좌변을 적절히 구성하면 중첩 구조의 값도 서로 다른 변수에 할당할 수 있다. 할당하는 방법은 어렵지 않다. 단순히 구조 분해 할당의 문법을 응용하면 된다.

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
let options = {
  size: {
    width: 100,
    height: 200
  },
  items: ["Cake", "Donut"],
  extra: true
};

let {
  size, // size 속성이 가리키는 객체 자체가 할당된다.
  size: { // size는 여기,
    width, // size의 속성 width의 value가 할당됨.
    height // size의 속성 height의 value가 할당됨.
  },
  items, // items 속성이 가리키는 배열 자체가 할당됨.
  items: [item1, item2], // items 배열의 각 요소가 할당됨.
  title = "Menu" // 분해하려는 객체에 title 프로퍼티가 없으므로 기본값을 사용함
} = options;

console.log(size);   // { width: 100, height: 200 }
console.log(items);  // [ 'Cake', 'Donut' ]
console.log(title);  // Menu
console.log(width);  // 100
console.log(height); // 200
console.log(item1);  // Cake
console.log(item2);  // Donut

매개변수 기본값

구조 분해 할당을 사용하지 않고 매개변수의 기본값을 설정하는 방법은 아래와 같다.

1
2
3
4
5
6
function showMenu(title = "Untitled", width = 200, height = 100, items = []) {
  // ...
}

showMenu("My Menu", ["Item1", "Item2"]); // 에러 발생. 인자와 매개변수가 상응하지 않음. 
showMenu("My Menu", undefined, undefined, ["Item1", "Item2"]);


이 경우 인자의 순서를 정확히 맞춰 주어야 한다. 기본값을 사용하기 위해 undefined를 인자로 넘겨주는 등 깔끔하지 못한 느낌을 준다. 이 때 구조 분해 할당 문법을 사용하면 아주 깔끔하게 함수의 기본값을 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 함수에 전달할 객체
let options = {
  title: "My menu",
  items: ["Item1", "Item2"]
};

// 똑똑한 함수는 전달받은 객체를 분해해 변수에 즉시 할당함
function showMenu({title = "Untitled", width = 200, height = 100, items = []}) {
  // title, items – 객체 options에서 가져옴
  // width, height – 기본값
  console.log( `${title} ${width} ${height}` ); // My Menu 200 100
  console.log( items ); // Item1, Item2
}

showMenu(options);


  • 위 예시에서 모든 함수의 매개변수 값을 기본값으로 사용하고 싶다면, 빈 객체를 명시적으로 인자로 넘겨주어야 한다.
    1
    2
      showMenu(); // 에러 발생
      showMenu({});
    


  • 빈 객체를 인자로 넘겨주는 코드가 지저분하다고 느껴진다면, 함수 매개변수 자체의 기본값을 빈 객체로 설정해주면 조금 더 깔끔한 코드가 된다.
    1
    2
    3
    4
      function showMenu({title = "Untitled", width = 200, height = 100, items = []} = {}) {
      	//...
      }
      showMenu(); // 정상적으로 동작한다.
    
0%