TIL [Spread Operator]

dlrbwls0302·2020년 12월 14일
0

MDN에서 발췌한 Spread 연산자

전개 구문을 사용하면 배열이나 문자열과 같이 반복 가능한 문자를 0개 이상의 인수 (함수로 호출할 경우) 또는 요소 (배열 리터럴의 경우)로 확장하여, 0개 이상의 키-값의 쌍으로 객체로 확장시킬 수 있습니다.

이것만 가지고는 이해할 수 없다 😥

Spread 연산자 구문

1. 함수 호출:

myFunction(...iterableObj);

2. 배열 리터럴과 문자열:

[...iterableObj, '4', 'five', 6];

3. 객체 리터럴:

let objClone = { ...obj };

이렇게 보니 최대한 원본인 배열이나 객체를 지키면서 다른곳에 복사하는 역할을 하는 것 같다. 그럼 더 살펴보겠다.

함수 호출은 배열의 엘리멘트를 함수의 인자로 사용할 때 쓰인다.

function myFunction(x, y, z) { }
var arr = [0, 1, 2];
myFunction(...arr); 

이렇게 되면 x, y, z라는 함수의 인자에 args[0], args[1], args[2]이 순서대로 할당된다. 그대신 배열의 인자 수와 함수의 인자 수가 같아야 한다.

function myFunction(v, w, x) { // 함수의 인자는 3개
 console.log(v); // 0
 console.log(w); // 1
 console.log(x); // undefined
} 
var arr = [0, 1]; // 배열의 엘리먼트는 2개
myFunction(...arr);

이렇게 할당되지 못한 함수의 인자는 undefined를 리턴한다.

배열 리터럴에서 전개

원래 참조 타입 데이터(배열, 객체, 함수 등)는 해당 변수에 값을 할당하는게 아닌 값이 있는 주소를 할당한다.

let arr = [0, 1, 2];
arr = newArr;
newArr[0] = 10;
arr; // [10, 1, 2] newArr를 바꿨는데 arr도 똑같이 바뀜

이렇게 arr를 newArr에 복사하는것은 해당 주소를 할당하기 때문에 newArr를 바꾸면 해당 주소에 저장된 값이 바뀌고, arr또한 그 주소를 계속 참조하고 있어서 newArr와 마찬가지로 변하게 된다.

1-1. 하지만 spread 연산자를 사용하게 되면 이것을 방지할 수 있게된다.

let arr = [1, 2, 3];
let newArr = [...arr]; // arr.slice() 와 유사
newArr.push(4); // [1, 2, 3, 4]
arr; // [1, 2, 3];

1-2. 코플릿 [배열 #7]


어떤 문자열을 getAllLetters라는 함수에 넣고 각 문자를 배열의 요소로 만들어야 한다. split이라는 함수를 써도 되지만 문제에 split을 쓰지 말라고 한다. 그래서 찾아보니 spread 함수를 이용하면 간단하게 풀 수 있다.

function getAllLetters(str) {
  return [...str]; 
}
console.log(getAllLetters('Radagast')); // ['R', 'a', 'd', 'a', 'g', 'a', 's', 't']

문자열을 배열에 넣고 spread함수를 쓰게되면 그 배열안에서 글자 하나하나가 요소가 되게 만들 수 있다.

3. 객체 리터럴에서의 전개

let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };
let clonedObj = { ...obj1 }; // { foo: "bar", x: 42 }
let mergedObj = { ...obj1, ...obj2 }; // { foo: 'baz', x: 42, y: 13 }
clonedObj.foo = 'lol';
console.log(clonedObj); // { foo: 'lol', x: 42}
console.log(obj1); // { foo: 'bar', x: 42 }

clonedObj.foo의 값을 바꿨지만 obj1.foo의 값은 그대로인 것을 알 수있다.

4. 만약 객체나 배열이 중첩된 데이터를 가지고 있다면?

let c = [1, 2, [3, [4, 5]]];
let d = [...c];

객체나 배열안의 원시형 데이터는 deep copy (원본과 복사한 데이터가 서로 영향 x)이고 객체나 배열안의 참조형 데이터는 shallow copy (원본과 복사한 데이터가 서로 같은 주소를 가르키기 때문에 서로 영향 o)를 한다고 생각하면 된다.

5. 만약 객체나 배열에서 중첩된 데이터들 까지 deep copy하고 싶다면?

let object = { 
  	       foo: 'bar', 
               value: 1, 
               profile: {
                          name: 'gildong', 
                          city: 'LA', 
                          age: 32
                         }
              };
let newObj = {
              ...obj, 
              profile: {
                         ...obj.profile, 
                         city: 'Seoul'
                       }
              };
console.log(object.profile.city) // LA
console.log(newObj.profile.city) // Seoul

중첩된 데이터도 spread 연산자로 복사해 버리니 (deep copy) newObj.profile.city = 'Seoul'로 바꿨지만 object에는 아무런 변화가 없다.

자료 출처:
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax

profile
오늘의 공부가 쌓여서 내일의 나를 만들어낸다.

0개의 댓글