키를 가진 데이터 여러 개를 하나의 엔티티에 저장할 땐 객체를, 컬렉션에 데이터를 순서대로 저장할 땐 배열을 사용한다.
개발을 하다 보면 함수에 객체나 배열을 전달해야 하는 경우가 생기곤한다.
가끔은 객체나 배열에 저장된 데이터 전제가 아닌 일부만 필요한 경우가 생기기도 한다.
이럴 때 객체나 배열을 변수로 '분해'할 수 있게 해주는 특별한 문법인 구조 분해 할당(destructuring assignment)을 사용할 수 있다.
이 외에도 매개변수가 많거나 매개변수 기본값이 필요한 경우 등에서 구조 분해(destructuring)는 그 진가를 발휘한다.
이제 인덱스를 이용해 배열에 접근하지 않고도 변수로 이름과 성을 사용할 수 있게 되었다.
아래 예시처럼 split 같은 반환 값이 배열인 메서드를 함께 활용해도 좋다.
배열의 요소를 직접 변수에 할당하는 것보다 코드 양이 줄어든다는 점만 다르다.
두 번째 요소는 생략되었지만, 세 번째 요소는 title 이라는 변수에 할당된 것을 확인할 수 있다. 할당할 변수에 할당된 것을 확인할 수 있다. 할당할 변수가 없기 때문에 네 번째 요소 역시 생략되었다.
아래와 같이 객체 프로퍼티도 가능하다.
이 메서드와 구조 분해를 조합하면 객체의 키와 값을 순회해 변수로 분해 할당할 수 있다.
맵에도 물론 이 메서드를 활용할 수 있다.
예시에선 임시 배열을 만들어 두 변수를 담고, 요소 순서를 교체해 배열을 분해하는 방식을 사용했다.
이 방식을 사용하면 두 개뿐만 아니라 그 이상의 변수에 담긴 값도 교환할 수 있다.
rest는 나머지 배열 요소들이 저장된 새로운 배열이 된다. rest 대신에 다른 이름을 사용해도 되는데, 변수 앞의 점 세개(...)와 변수가 가장 마지막에 위치해야 한다는 점을 주의해야한다.
=를 이용하면 할당할 값이 없을 때 기본으로 할당해 줄 값인 '기본값(default value)'을 성정할 수 있다.
복잡한 표현식이나 함수 호출도 기본값이 될 수 있다. 이렇게 기본식으로 표현식이나 함수를 설정하면 할당할 값이 없을 때 표현식이 평가되거나 함수가 호출된다.
기본값으로 두 개의 prompt 함수를 할당한 예시를 살펴보자. 값이 제공되지 않았을 때만 함수가 호출되므로, prompt는 한 번만 호출된다.
let {var1, var2} = {var1:.., var2:..}
할당 연산자 우측엔 분해하고자 하는 객체를, 좌측엔 상응하는 객체 프로퍼티의 '패턴'을 넣는다. 분해하려는 객체 프로퍼티의 키 목록을 패턴으로 사용하는 예시를 살펴보자.
프로퍼티 options.title과 options.width, options.height에 저장된 값이 상응하는 변수에 할당된 것을 확인할 수 있다. 참고로 순서는 중요하지 않는다. 아래와 같이 작성해도 위 예시와 동일하게 동작한다.
할당 연산자 좌측엔 좀 더 복잡한 패턴이 올 수도 있다. 분해하려는 객체의 프로퍼티와 변수의 연결을 원하는 대로 조정할 수도 있다.
객체 프로퍼티를 프로퍼티 키와 다른 이름을 가진 변수에 저장해보자. options.width를 w라는 변수에 저장하는 식으로 말이다. 좌측 패턴에 콜론(:)을 사용하면 원하는 목표를 달성할 수 있다.
콜론은 '분해하려는 객체의 프로퍼티: 목표 변수'와 같은 형태로 사용한다. 위 예시에선 프로퍼티 width를 변수 w에, 프로퍼티 height를 변수 h에 저장했다. 프로퍼티 title은 동일한 이름을 가진 변수 title에 저장된다.
프로퍼티가 없는 경우를 대비하여 =을 사용해 기본값을 설정하는 것도 가능하다.
배열 혹은 함수의 매개변수에서 했던 것처럼 객체에도 표현식이나 함수 호출을 기본값으로 할당할 수 있다. 물론 표현식이나 함수는 값이 제공되지 않았을 때 평가 혹은 실행된다.
아래 예시를 실행하면 width 값만 물어보고 title 값은 물어보지 않았다.
클론과 할당 연산자를 동시에 사용할 수도 있다.
프로퍼티가 많은 복잡한 객체에서 원하는 정보만 뽑아오는 것도 가능하다.
나머지 패턴(rest pattern)을 사용하면 배열에서 했던 것처럼 나머지 프로퍼티를 어딘가에 할당하는 게 가능하다. 참고로 모던 브라우저는 나머지 패턴을 지원하지만, IE를 비롯한 몇몇 구식 브라우저는 나머지 패턴을 지원하지 않으므로 주의해서 사용해야 한다. 물론 바벨(Babel)을 이용하면 되긴하다.
잘못된 코드:
자바스크립트는 표현식 안에 있지 않으면서 주요 코드 흐름 상에 있는 {...}를 코드 블록으로 인식한다. 코드 블록의 본래 용도는 아래와 같이 문자(statement)를 묶는 것이다.
위쪽 예시엔 구조 분해 할당을 위해 사용한 {...}를 자바스크립트가 코드 블록으로 인식해서 에러가 발생하였다.
에러를 해결하려면 할당문을 괄호 (...)로 감싸 자바스크립트가 {...} 를 코드 블록이 아닌 표현식으로 해석된다.
아래 예시에서 객체 options의 size 프로퍼티 값은 또 다른 객체이다. items 프로퍼티는 배열을 값으로 가지고 있다. 대입 연산자 좌측의 패턴은 정보를 추출하려는 객체 options와 같은 구조를 갖추고 있다.
extra(할당 연산자 좌측의 패턴에는 없음)를 제외한 options 객체의 모든 프로퍼티가 상응하는 변수에 할당되었다.
변수 width, height, item1, item2엔 원하는 값이, title엔 기본값이 저장되었다.
그런데 위 예시에서 size와 items 전용 변수는 없다는 점에 유의하자.
전용 변수 대신 우리는 size와 items 안의 정보를 변수에 할당하였다.
먼저 리팩토링 전의 메뉴 생성 함수를 살펴보자.
꽤나 지저분해 보인다. 매개변수가 많아질수록 가독성은 더 떨어질 것이다.
구조 분해는 이럴 때 구세주가 된다.
매개변수 모두를 객체에 모아 함수에 전달해, 함수가 전달받은 객체를 분해하여 할당하고 원하는 작업을 수행할 수 있도록 함수를 리팩토링해보자.
중첩 객체와 콜론을 조합하면 좀 더 복잡한 구조 분해도 가능하다.
이렇게 똑똑한 함수 매개변수 문법은 구조 분해 할당 문법과 동일하다.
function({
incomingProperty: varName = defaultValue
...
})
매개변수로 전달된 객체의 프로퍼티 incomingProperty는 varName에 할당된다. 만약 값이 없다면 defaultValue가 기본값으로 사용될 것이다.
참고로 이렇게 매개변수를 구조 분해할 땐, 반드시 인수가 전달된다고 가정되고 사용된다는 점에 유의하자. 모든 인수에 기본값을 할당해 주려면 빈 객체를 명시적으로 전달해야한다.
이 문제를 예방하려면 빈 객체 {}를 인수 전체의 기본값으로 만들면 된다.
이렇게 인수 객체의 기본값을 빈 객체 {}로 설정하면 어떤 경우든 분해할 것이 생겨서 함수에 인수를 하나도 전달하지 않아도 에러가 발생하지 않는다.