[ES6] 펼침연산자(전개연산자, Spread Syntax, Spread Operator)

권준혁·2020년 11월 1일
0

javascript

목록 보기
5/19
post-thumbnail
post-custom-banner

Spread Syntax(이하 펼침연산자) 대해서 다루겠습니다.

const staff = [
    {name : 'John', position : 'musician'},
    {name : 'Davis',position : 'engineer'},
    {name : 'Theo',position : 'cleaner'},
    {name : 'Daniel',position : 'engineer'},
    {name : 'Bradley',position  : 'actor'},
    {name : 'Rosie',position  : 'office clerk'},
]

const staff는 객체요소를 가진 배열입니다.
콘솔에 먼저 출력해보겠습니다

console.log(staff)
/*
[
  { name: 'John', position: 'musician' },
  { name: 'Davis', position: 'engineer' },
  { name: 'Theo', position: 'cleaner' },
  { name: 'Daniel', position: 'engineer' },
  { name: 'Bradley', position: 'actor' },
  { name: 'Rosie', position: 'office clerk' }
]
*/

console.log(...staff)
/*
{ name: 'John', position: 'musician' } { name: 'Davis', position: 'engineer' } { name: 'Theo', position: 'cleaner' } { name: 'Daniel', position: 'engineer' } { name: 'Bradley', position: 'actor' } { name: 'Rosie', position: 'office clerk' }
*/

두 로그를 비교해보면
펼침연산자를 사용한 ...staff 는 배열내의 요소들을 하나씩 나열해줍니다. (이 자체로 배열이 아닙니다.)
원래대로라면 for문을 사용해 순회했어야 하지만 간단한 표현으로 원하는 데이터형태를 출력할 수 있을 것 같습니다.

  • 처음에 작성했던 객체요소를 가진 배열을 표현하려면 [...staff]로 표현할 수 있습니다.
  • 객체요소들을 감싼 객체를 표현하려면 {...staff}로 표현할 수 있습니다.

그럼 이제 본격적으로 살펴보겠습니다.

펼침연산자를 사용할 때의 이점에 대해 알아보겠습니다.

펼침연산자는 기존의 코드를 효과적이고 효율적으로 대체합니다.

1. 가변인수 - apply() 대체 (배열요소를 함수의 인수로 사용하고자 할때)

2. 복사하기 - 복사본으로 원본을 조작하지않고 정렬하기

3. 객체 펼침연산자 - Object.assign() 대체

4. 배열 펼침연산자 - 배열리터럴 내에서의 사용 (삽입)

다른 장점들도 있지만 이정도만 정리하겠습니다.

1. 가변인수 - Function.prototype.apply() 대체하기

apply()함수는 가변인수를 허용하는 함수뒤에 붙여서 배열을 인수로 넣을 수 있게 해줍니다.

array에 요소를 추가하는 push()메소드를 예로 들어보겠습니다.
push()메소드는 가변인수를 허용하는 함수 입니다.
이렇게 push(1,2,3,4,5,6,7, ... ,100) 많은 인수를 허용하는 함수입니다.

처음의 예제 데이터로 돌아가서
const staff 배열에 신입 회원 100명(newList라고 하겠습니다)을 추가하고 싶다면 어떻게 해야할까요
concat() 메서드를 사용하게되면 복사본을 반환하기 때문에 사용하지 않겠습니다.
우리는 원본을 조작하려고 합니다.

  • staff.push(newList)를 해보겠습니다. 다음은 출력된 로그입니다.
    [
    { name: 'John', position: 'musician' },
    { name: 'Davis', position: 'engineer' },
    { name: 'Theo', position: 'cleaner' },
    { name: 'Daniel', position: 'engineer' },
    { name: 'Bradley', position: 'actor' },
    { name: 'Rosie', position: 'office clerk' },
    [
     { name: 'A', position: 'warrior' },
     { name: 'B', position: 'magician' }
     ...
     { name: 'ZZ', position: 'thief' }
    ]
    ]

원하는 결과가 아닙니다

반복문으로 하나씩 처리할 수 도 있겠습니다만
(for 문으로 100번실행.............ㅜㅜ)

1. apply()를 사용할까요?
staff.push.apply(staff,newList)

2. 간단하게 펼침연산자를 사용하면 됩니다.
staff.push(...newList)

가변인수에 펼침연산자를 넣어 간단하게 성공했습니다!


2. 복사 - 복사본으로 원본을 조작하지않고 정렬하기

const staff의 직원 목록에서 이름을 오름차순으로 정렬해봅시다.
sort() 함수를 사용할 텐데 이 함수는 원본을 조작 합니다.

먼저 정렬함수를 작성합니다. sort()함수의 인수로 사용됩니다.

function sortByName(a,b) {
    if(a.name === b.name) {
        return 0;
    }
    return a.name > b.name? 1: -1;
}

간단히 설명하면 반환값이 0보다 작을경우 (-1) 경우 a가 앞으로
반환값이 0보다 클 경우 (1) b가 앞으로 옵니다.
배열요소가 객체기 때문에 a.name으로 접근합니다.

이제 정렬해보겠습니다.
staff.sort(sortByName)을 실행하면 이름에 따라 오름차순으로 정렬됩니다.
하지만 원본을 조작해버렸습니다.

조작하지 않으려면 역시 펼침연산자를 사용해 복사하면 됩니다.

const applied = [...staff].sort(sortByName) 

applied에 정렬된 배열이 복사가 됐습니다. 이제 안심하고 복사된 배열을 사용할 수 있습니다.


3. 객체 펼침연산자 - Object.assign() 대체하기 (갱신)

MDN에서 Object.assgin()에대해 자세히보기
Object.assign(target, source)은 target에 source의 속성들을 복사해 덮어씌우고 target을 반환합니다.
target에 빈 객체나 빈 배열을 넣어 원본조작을 피할 수 있습니다.

Object.assgin()은 두 객체리터럴을 merge(병합) 하는데 유용합니다.

defaultValue = {
    name : 'anonymous',
    gender : 'unknown'
}
newValue = {
    name : 'Jack',
        gender : 'male'
}
const mergedValue = Object.assign(defaultValue , newValue)

mergedValuedefaultValue { name: 'Jack', gender: 'male' } 가 됩니다.
defaultValue의 조작을 피하려면 Object.assign({},defaultValue , newValue) 하면됩니다.

더 간단한 대안은 역시 펼침연산자입니다

console.log({...defaultValue, ...newValue})

객체리터럴의 key값에 해당하는 name, gender 속성이 같다면 병합됩니다. 함수가 아니므로 당연히 속성의 개수에 제한도 없으며, 표현식으로 간단하게 원하는 결과를 얻을 수 있습니다.


4. 배열 펼침연산자 - 배열리터럴 내에서의 사용 (삽입)

펼침연산자를 사용하지 않는 경우 splice() 메서드로 할 수 있습니다.
MDN 문서에서 splice()자세히보기

하지만 펼침연산자를 통해 원하는 곳에 쉽게 삽입할 수 있습니다. 읽을 때도 더욱 직관적입니다.

const put = [2,3]
const arr = [1, ...put,4,5]
console.log(arr)
// [1,2,3,4,5]

추가적인 사용

  1. 나머지 매개변수
  2. 해체할당에서 활용하기

1. 나머지 매개변수

1-1. 나머지 매개변수로 가변인수를 갖는 함수를 간단하게 작성할 수 있습니다.

이번에는 길이 유효성검사를 하는 예제를 해보겠습니다.

function validateCharacterCount(max, ...items) {
    return items.every(item => item.length < max);
}

첫 번째 인수로 전달한 길이보다 ...items목록의 각 요소의 길이가 작으면 true를 반환합니다.
MDN에서 every() 자세히보기

 validateCharacterCount(10, 'abcdefg')     // true
 validateCharacterCount(10, ...someList)     // true or false by length
 validateCharacterCount(10, 'abcdefg' , 'hijklm')     // true

1-2. 나머지 매개변수로 디버깅에 활용하기

map메서드의 콜백함수에서 몇 개의 인수가 전달될까요?
저는 item, index 2개가 전달 된다고 알고 있었습니다.

['Spring' , 'Summer' , 'fall' , 'Winter'].map((item, ...rest)=>{
    console.log(item)
    console.log(rest)
}) 

/*
Spring
[ 0, [ 'Spring', 'Summer', 'fall', 'Winter' ] ]
Summer
[ 1, [ 'Spring', 'Summer', 'fall', 'Winter' ] ]
fall
[ 2, [ 'Spring', 'Summer', 'fall', 'Winter' ] ]
Winter
[ 3, [ 'Spring', 'Summer', 'fall', 'Winter' ] ]
*/

item, index뿐 아니라 전체 목록을 반환하기도 합니다. map뿐 아니라 궁금했던 매서드들에서 활용해 볼 수 있습니다.


2. 해체할당에서 활용하기

해체할당은 객체나 배열의 필요한 요소를 key값이나 index에 따라 추출해내는 기능입니다.

2-1. 객체리터럴에서 사용하기

추출해내는 기준은 key값입니다.
해당 객체의 name속성만 빼서 (해체) name에 담아보겠습니다 (할당).

const {name} = {name : 'Jack' , gender : 'male' , interest : 'game'}
console.log(name) // Jack

이미 선언된 변수에도 다음과 같이 해체할당 할 수 있습니다.

const profile = {name : 'Jack' , gender : 'male' , interest : 'game'}
let name;
({name} = profile)
console.log(name)  // Jack

정의되지 않은 속성명을 해체할당 하려고하면 undefined가 반환됩니다.

그럼 펼침연산자로 나머지 속성과 값을 받아보겠습니다.

const profile = {name : 'Jack' , gender : 'male' , interest : 'game'}
const {name, friends, ...rest} = profile
console.log(friends)  // undefined
console.log(rest)  // { gender: 'male', interest: 'game' }

friends는 undefined입니다 !!

2-2. 배열리터럴에서 사용하기

유명한 라이브러리 React를 해보신 분이라면 React hook의 State에서 많이봤던 기능입니다. 저는 React에서 이 기능을 처음 접해봤습니다.

const [first,second] = [1,2,3,4,5] 
console.log(first, second)        // 1 2

배열에서의 해체할당은 배열의 index값이 기준이 됩니다.

const [first,second,...rest] = [1,2,3,4,5] 
console.log(first, second)        // 1 2
console.log(rest)        // [3,4,5]

마지막으로 주의사항은
나머지 매개변수나 해체할당의 경우 항상 마지막 값이여야 한다는 것입니다.

// !!!!!!!! ERROR !!!!!!!!!
const [...rest , last] = someArray

다음의 경우 에러가 발생합니다!

profile
웹 프론트엔드, RN앱 개발자입니다.
post-custom-banner

0개의 댓글