확산 연산자와 구조 분해 할당

JaeungE·2021년 7월 13일
0

JavaScript

목록 보기
9/16
post-thumbnail

이번 포스팅에서는 ES6에서 새롭게 추가된 확산 연산자구조 분해 할당에 대해서 알아볼 예정이다.

구조 분해 할당해체 할당 혹은 비구조화 할당이라고도 부르지만, 여기서는 MDN Web Docs에서 번역된 구조 분해 할당이라는 표현을 사용하도록 하겠다!😉

그렇게 어려운 내용은 아니면서 강력한 기능이니, 어떤 기능인지 한 번 보도록 하자!



확산 연산자(Spread Operator)

확산 연산자란, 식별자 앞에 붙여서 배열 혹은 문자열 등 iterable한 객체의 요소들을 전개할 수 있는 연산자이다!

말로만 보면 어떻게 사용하고, 무슨 소리인지도 잘 이해가 되지 않는다... 코드를 보며 이해해보자.


const arr = [1, 2, 3, 4, 5];
const str = 'Hello World!';

console.log(...arr); // 1 2 3 4 5
console.log(...str); // H e l l o   W o r l d !

이렇게 배열이나 문자열의 식별자 앞에 확산 연산자를 이용해 각 요소를 console에 출력해주는 것을 볼 수 있다.😲

이것을 이용하면 간단하게 배열의 복사 및 합치기도 가능하다. 아래의 코드를 보도록 하자!


const arr1 = [1, 2, 3, 4, 5];
let arr2 = arr1;

const sArr1 = [1, 2, 3, 4, 5];
let sArr2 = [...sArr1];

arr2[0] = 0;
sArr2[0] = 0;

console.log(...arr1); // 0 2 3 4 5
console.log(...arr2); // 0 2 3 4 5
console.log(...sArr1); // 1 2 3 4 5
console.log(...sArr2); // 0 2 3 4 5

확산 연산자를 이용한 것과 아닌 것의 차이를 나타내기 위한 코드이다.

배열은 기본적으로 참조형 타입이므로, 단순히 해당 배열을 가리켜서 복사하게 되면 얕은 복사를 해서 원본 배열이 조작될 우려가 있다.

하지만 확산 연산자를 이용하면 깊은 복사를 하므로, 원본 배열이 손상되지 않는 것을 볼 수 있다!

물론 1차원 배열의 경우에만 가능하고, 다차원 배열에서는 깊은 복사를 보장할 수 없으므로 주의하자.

이번엔 배열의 요소를 복사하여 새로운 배열을 만드는 것을 보도록 하자!😆


let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];

let arr3 = [...arr1, ...arr2];
arr1 = [...arr2, ...arr1];

console.log(...arr3); // 1 2 3 4 5 6
console.log(...arr1); // 4 5 6 1 2 3

이처럼 확산 연산자를 이용하면 Array.prototype 에 있는 splice()concat() 메서드 없이도 배열에 새로운 요소를 추가할 수 있다는 것을 알아두자!



Rest 파라미터

확산 연산자iterable한 객체 말고도, 함수의 매개 변수에도 사용이 가능하다.

함수의 마지막 매개 변수에 확산 연산자를 이용해서, 명시하지 않은 매개 변수에 대해서도 다양한 처리가 가능하다.

아래 코드를 통해 어떤 의미인지 확인해보자!


const func = function(one, two, ...more){
    console.log(one); // One
    console.log(two); // Two
    console.log(more); // ['Three', 'Four', 'Five']
};

func('One', 'Two', 'Three', 'Four', 'Five');

확산 연산자를 이용했더니 onetwo 뒤에 나머지 전달 인자들이 배열 형태로 넘어온 것을 확인할 수 있다!😮

또한, Rest 파라미터는 위와 같이 항상 매개 변수의 마지막에 와야 한다는 점을 명심하자. 그렇지 않으면 에러가 발생한다.

그리고 Rest 파라미터배열 형태라는 점을 기억하고, 아래의 다른 활용 예제도 보도록 하자!


const print = (...parameters) => {
    parameters.forEach(function(person) {
        console.log(person); // Jake Thomas Joseph
    });
};

print('Jake', 'Thomas', 'Joseph');

이전에 ES6의 함수와 화살표 함수에서, 화살표 함수는 Arguments 객체를 사용할 수 없다고 했었다.

하지만 위의 코드를 보면 Arguments 객체를 이용한 것처럼 동작이 가능하고, Array.prototype에 정의되어있는 forEach() 메서드도 사용이 가능할 수 있다!😨

왜냐하면, Rest 파라미터Arguments 객체처럼 유사 배열 객체가 아니라 Array의 인스턴스, 즉 배열 객체이기 때문에 가능한 것이다.

그러니 ES6에서는 번거로운 Arguments 객체 대신 Rest 파라미터를 적극 이용하도록 하자!





구조 분해 할당(Destructuring assignment)

구조 분해 할당이란, 객체의 프로퍼티 혹은 배열의 요소를 분해해서 변수에 대입하는 것을 말한다.

배열 분해와 객체 분해가 조금씩 다르니 나눠서 설명하도록 하겠다!😊



배열 구조 분해


const arr = ['one', 'two', 'three', 'four', 'five'];
let first, second;

[first, second] = arr; // or let [first, second] = arr

console.log(first); // one
console.log(second); // two

코드를 보면 arr 배열의 첫 번째와 두 번째 요소를 firstsecond라는 이름으로 분해하여 출력하는 것을 확인할 수 있다.

배열 구조 분해는 이처럼 배열의 첫 요소부터 분해하게 된다.

이 외에도 다양한 특징이 있는데 한 번 살펴보자!😀


기본값

구조 분해시 할당되지 않은 값에 대해서 아래처럼 기본값을 설정할 수 있다.


const arr = [1];
let [first, second = 2] = arr;

console.log(first); // 1
console.log(second); // 2

변수 값 교환

구조 분해 할당을 이용해서 임시 변수 없이도 값의 교환이 가능하다.


const arr = [1, 2];
let [first, second] = arr;
[first, second] = [second, first];

console.log(first); // 2
console.log(second); // 1

값 무시

구조 분해 할당을 할 때, 필요 없는 값을 무시할 수 있다.


const arr = [1, 2, 3];
let [first, , third] = arr;

console.log(first); // 1
console.log(third); // 3

Rest 파라미터

위에서 설명했던 확산 연산자구조 분해 할당에도 이용할 수 있다.

하지만 Rest 파라미터와 마찬가지로 항상 마지막에 사용해야 한다는 것을 잊지 말자!😠


const arr = [1, 2, 3, 4, 5];
let [first, ...more] = arr;

console.log(first); // 1
console.log(more); // [2, 3, 4, 5]

이제 배열 구조 분해를 마치고, 이제 객체 구조 분해로 넘어가보도록 하겠다!





객체 구조 분해

배열 구조 분해와 큰 차이점은 없다.

단지 배열 분해는 첫 요소부터 하나씩 분해했다면, 객체 분해는 프로퍼티의 key를 기준으로 분해한다고 생각하면 된다.

역시 눈으로 보는 게 제일 빠르다. 아래 코드를 참고하도록 하자!🙂


const obj = {
    num : 1,
    str : 'Hello'
};

let {n, num, s, str} = obj;
console.log(n); // undefined
console.log(num); // 1
console.log(s); // undefined
console.log(str); // str

위에서 설명한 대로 프로퍼티의 key를 기준으로 분해하기 때문에, 순서가 바뀌어도 분해하는데 지장이 없는 것을 볼 수 있다.

하지만 배열 구조 분해와 달리 주의해야 할 점이 있다.


const obj = {
    num : 1,
    str : 'Hello'
};

let num, str;

{num, str} = obj; // Syntax Error

console.log(num);
console.log(str);

바로 위의 코드처럼 선언과 할당을 분리할 때 일어나게 되는데, {num, str} = obj;구조 분해 할당이 아니라 그냥 좌변을 블록으로 인식하기 때문이다.

따라서 객체 구조 분해시 선언과 할당을 분리하고자 한다면 다음 코드처럼 수정하도록 하자!🙂


const obj = {
    num : 1,
    str : 'Hello'
};

let num, str;

({num, str} = obj);

console.log(num); // 1
console.log(str); // Hello

이렇게 소괄호로 감싸주면 에러가 발생하지 않고 정상적으로 구조 분해 할당이 이루어지는 것을 확인할 수 있다.

그럼 이제 객체 구조 분해의 기능을 확인하러 가보자!



기본값

배열과 크게 다르지 않아서 그냥 넘어가도 되는 부분이긴 하지만 그래도 정리해두겠다.


const obj = {
    myName : 'jake',
    weight : '75',
    height : '180'
};

let {myName, age = 25, weight, height} = obj;

console.log(myName); // jake
console.log(age); // 25
console.log(weight); // 75
console.log(height); // 180

존재하지 않는 프로퍼티인 경우 위처럼 기본값을 설정해줄 수 있다.


변수 이름 변경

프로퍼티의 key를 기준으로 분해를 하는 객체 구조 분해의 특성상, 프로퍼티와 변수의 이름을 다르게 해주고 싶은 경우가 생길 수 있다.😓

그래서 객체 구조 분해:(콜론)을 이용해 다음과 같이 변수 이름을 변경할 수 있다!


const obj = {
    AnimalName : 'bbokbbok',
    WhatAnimalAge : '18',
    WhatBreed : 'Yorkshire Terrier'
};

let {AnimalName : dogName, WhatAnimalAge : age, WhatBreed : breed} = obj;

console.log(dogName); // bbokbbok
console.log(age); // 18
console.log(breed); // Yorkshire Terrier

정상적으로 변경된 것을 확인할 수 있다.





구조 분해 할당을 이용하면 위에서 설명했던 배열과 객체뿐만 아니라, iterable한 객체들은 모두 분해가 가능하다.

아직은 어디에 써야 할지 확 와닿는 기능은 아니지만, 추가된 이유는 분명 있을 테니 필요할 때 적재적소에 활용할 수 있도록 잊지 말고 기억해놔야겠다!😊





참고 자료

[전개 구문 - JavaScript | MDN]
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax

[구조 분해 할당 - JavaScript | MDN]
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

0개의 댓글