• Blog
  • Projects
  • Resume
profile_image

[JavaScript] 전개 연산자

JavaScript

2021.01.18

정의

  1. ECMAScript6(2015)에서 새로 추가된 전개 연산자(Spread Operator)란 객체나 배열의 값을 하나 하나 넘기는 용도로 사용할 수 있다.
  2. 직관적이고, 배열의 아무곳에 추가 가능하다.
  3. 전개 구문 (spread 프로퍼티인 경우 제외) 은 iterable 객체에만 적용 가능하다.
    • 이터러블(iterable)은 Array, String, Map, Set, DOM구조
    • iterator를 생성해서 next()로 순회할 수 있는 자료구조가 이터러블이라고 생각하면 됨!
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [7, 8, 9];

// ES5
const arrWrap = arr1.concat(arr2, arr3);
console.log(arrWrap); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

// ES6
const arrWrap2 = [...arr1, ...arr2, ...arr3];
console.log(arrWrap2); // [1, 2, 3, 4, 5, 6, 7, 8, 9]


구문

  • 함수 호출
    myFunction(...iterableObj);
    
  • 배열 리터럴과 문자열
    [...iterableObj, '4', 'five', 6];
    
  • 객체 리터럴(ECMAScript 2018에서 추가):
    let objClone = {...obj};
    


예제

함수 호출에서의 전개

  • apply() 대체

    • 일반적으로 배열의 엘리먼트를 함수의 인수로 사용하고자 할 때 Function.prototype.apply() 를 사용했었다.

      function myFunction(x, y, z) {}
      var args = [0, 1, 2];
      myFunction.apply(null, args);
      
      // 전개 구문을 사용해 ▲ 코드는 ▼과 같이 작성될 수 있다.
      
      function myFunction(x, y, z) {}
      var args = [0, 1, 2];
      myFunction(...args);
      
    • 인수 목록의 모든 인수는 전개 구문을 사용할 수 있으며, 여러번 사용될 수 있다.

      function myFunction(v, w, x, y, z) {}
      var args = [0, 1];
      myFunction(-1, ...args, 2, ...[3]);
      
  • new에 적용

    • new를 사용해 생성자를 호출 할 때, 배열과 apply직접 사용하는 것은 불가능했었다.
      전개 구문은 배열을 new와 함께 쉽게 사용될 수 있다.
      var dateFields = [1970, 0, 1]; // 1 Jan 1970
      var d = new Date(...dateFields);
      

배열 리터럴에서의 전개

  • 더 강력한 배열 리터럴

    • 전개 구문 없이, 이미 존재하는 배열을 일부로 하는 새로운 배열을 생성하기에, 배열 리터럴 문법은 더 이상 충분하지 않으며
      push(), splice(), concat() 등의 조합을 사용하는 대신 명령형 코드를 사용해야 했다. 전개 구문으로 이는 훨씬 더 간결해졌다.
      var parts = ['shoulders', 'knees'];
      var lyrics = ['head', ...parts, 'and', 'toes'];
      // ["head", "shoulders", "knees", "and", "toes"]
      

      인수 목록을 위한 spread 처럼, ... 은 배열 리터럴의 어디에서든 사용될 수 있으며 여러번 사용될 수도 있다.

  • 배열 복사

    • Spread 문법은 배열을 복사할 때 1 레벨 깊이에서 효과적으로 동작함.

      var arr = [1, 2, 3];
      var arr2 = [...arr]; // arr.slice() 와 유사
      arr2.push(4);
      
      // arr2 은 [1, 2, 3, 4] 이 됨
      // arr 은 영향을 받지 않고 남아 있음
      
    • 위 예제와 달리 이 예제와 같이 다차원 배열을 복사하는것에는 적합하지 않을 수 있음.

      var a = [[1], [2], [3]];
      var b = [...a];
      b.shift().shift(); // 1
      // 이제 배열 a 도 영향을 받음: [[], [2], [3]]
      
  • 배열을 연결하는 더 나은 방법

    • Array.prototype.concat() 은 배열을 존재하는 배열의 끝에 이어붙이는데 종종 사용된다.
      • 전개 구문 없이 사용
        var arr1 = [0, 1, 2];
        var arr2 = [3, 4, 5];
        // arr2 의 모든 항목을 arr1 에 붙임
        arr1 = arr1.concat(arr2);
        
      • 전개 구문 사용
        var arr1 = [0, 1, 2];
        var arr2 = [3, 4, 5];
        arr1 = [...arr1, ...arr2]; // arr1 은 이제 [0, 1, 2, 3, 4, 5]
        
    • Array.prototype.unshift()는 존재하는 배열의 시작 지점에 배열의 값들을 삽입하는데 종종 사용된다.
      • 전개 구문 없이 사용
        var arr1 = [0, 1, 2];
        var arr2 = [3, 4, 5];
        // arr2 의 모든 항목을 arr1 의 앞에 붙임
        Array.prototype.unshift.apply(arr1, arr2); // arr1 은 이제 [3, 4, 5, 0, 1, 2] 가 됨
        
      • 전개 구문 사용
        var arr1 = [0, 1, 2];
        var arr2 = [3, 4, 5];
        arr1 = [...arr2, ...arr1]; // arr1 은 이제 [3, 4, 5, 0, 1, 2] 가 됨
        

객체 리터럴에서의 전개

  • 얕은 복제(prototype 제외) 또는 객체의 병합은 이제 Object.assign() 보다 더 짧은 문법을 사용해 가능.

    var obj1 = {foo: 'bar', x: 42};
    var obj2 = {foo: 'baz', y: 13};
    
    var clonedObj = {...obj1};
    // Object { foo: "bar", x: 42 }
    
    var mergedObj = {...obj1, ...obj2};
    // Object { foo: "baz", x: 42, y: 13 }
    
  • 아래 예제를 보면, 전개 구문은 예상대로 동작하지 않음! 나머지 매개변수로 인해, 인수 배열을 객체 리터럴로 전개한다.

    var obj1 = {foo: 'bar', x: 42};
    var obj2 = {foo: 'baz', y: 13};
    const merge = (...objects) => ({...objects});
    
    var mergedObj = merge(obj1, obj2);
    // Object { 0: { foo: 'bar', x: 42 }, 1: { foo: 'baz', y: 13 } }
    
    var mergedObj = merge({}, obj1, obj2);
    // Object { 0: {}, 1: { foo: 'bar', x: 42 }, 2: { foo: 'baz', y: 13 } }
    
  • 객체 리터럴에서의 전개 연산자는..

    • Object.assign() 은 setters 를 트리거하지만 전개 구문은 그렇지 않음을 유의.
    • Object.assign() 함수를 대체하거나 흉내낼 수 없음을 유의.


기타..(ETC)

Set 객체를 Array로 변환하는 방법

  • Array.from()
    Array.from 함수는 유사배열객체(array-like object)나 반복가능객체(iterable object)를
    얕은 복사(shallow copy)하여 새로운 배열(Array) 객체를 만들어줌

    • 유사배열객체(array-like object) : length 속성과 index element를 가지는 객체
    • 반복가능객체(iterable object) : 배열을 일반화한 객체 ex)Map, Set
    const set = new Set([1, 2, 3]);
    const arr = Array.from(set);
    console.log(Array.isArray(arr)); // true
    console.log(arr); // [1, 2, 3]
    
  • Spread Operator(전개 연산자)
    Spread Operator는 ES6의 문법으로 배열이나 문자열과 같이 반복가능한 객체를 하나씩 펼쳐서 리턴.
    '...'과 같이 점 3개로 표시함.

    const set = new Set([1, 2, 3]);
    const arr = [...set];
    console.log(Array.isArray(arr)); // true
    console.log(arr); // [1, 2, 3]
    // 전개 연산자(...) 사용하여 Set 객체의 값들을 하나씩 꺼내서, 새로운 배열의 원소로 넣어서, arr 변수에 저장함
    
  • forEach

    const set = new Set([1, 2, 3]);
    const arr = [];
    
    set.forEach((element) => {
      arr.push(element);
    });
    
    console.log(Array.isArray(arr)); // true
    console.log(arr); // [1, 2, 3]
    



참고 자료