Spread Operator는 얕은 복사일까 깊은 복사일까

짱유경·2021년 11월 26일
15

JavaScript

목록 보기
1/3
post-thumbnail

💾 객체의 복사

객체의 값을 복사한다음 프로퍼티의 내용을 변경하려할 떄, 단순히 객체를 복사한다음 프로퍼티를 수정하면 원본 객체의 프로퍼티까지 변경이된다.

var obj = { a: "안녕하세요?" };
var obj2 = obj;

console.log(obj); // { a: "안녕하세요?" };
console.log(obj2); // { a: "안녕하세요?" };

obj2.a = "반갑습니다.";

console.log(obj); // { a: "반갑습니다." };
console.log(obj2); // { a: "반갑습니다." };

이는 obj2로 복사한 객체가 값을 새로 할당한게 아니라 obj 객체의 주소값을 단순히 참조하고 있어 같은 값이므로 true를 반환하는 현상이 나타난다. 이렇게 원래값과 복사한 값이 같은 주소값을 보고있으면 얕은 복사라고 한다.

// 참조하고 있는 주소값이 같음.
console.log(obj === obj2); // true

📍 Spread Operator

그래서 완전히 원본 주소와 참조를 끊어주는 방법을 사용해야 내부 프로퍼티 값을 변경해도 복사한 원본 객체의 값이 바뀌지 않는다.
이때 원본의 값을 변경시키지 않고, 복사한 객체의 프로퍼티 값만 변경하는 방법이 있는데 그중 하나가 바로 Spread Operator(...)를 이용하는 방법이다.

var obj = { a: "안녕하세요?" };
var obj2 = { ...obj, a: "반갑습니다." };

console.log(obj); // { a: "안녕하세요?" };
console.log(obj2); // { a: "반갑습니다?" };

이제 obj2는 단순히 obj의 주소값을 참조만 하는게 아니라 새로운 주소값에 값을 할당하므로 false가 나타난다.

console.log(obj === obj2); // flase

그럼 Spread Operator는 얕은복사일까? 깊은복사일까?

참고: Spread 문법은 배열을 복사할 때 1 레벨 깊이에서 효과적으로 동작합니다. 그러므로, 다음 예제와 같이 다차원 배열을 복사하는것에는 적합하지 않을 수 있습니다. (Object.assign() 과 전개 구문이 동일합니다)
출처 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax

위의 문서에서 보면, 다차원 배열을 복사할땐 적합하지 않다고 얘기하고 있다.

var a = [[1], [2], [3]];
var b = [...a];
b.shift().shift(); // 1

ECMA Script 명세에서 Spread Operator의 동작방식을 살펴보면, 빈 List를 생성해 값을 넣는 방식으로, 가장 바깥의 배열만 깊게 복사하는것으로 유추할 수 있다.

  1. Let list be an empty List.
  2. Let spreadRef be the result of evaluating AssignmentExpression.
  3. Let spreadObj be GetValue(spreadRef).
  4. Let iterator be GetIterator(spreadObj).
  5. ReturnIfAbrupt(iterator).
  6. Repeat
    a. Let next be IteratorStep(iterator).
    b. ReturnIfAbrupt(next).
    c. If next is false, return list.
    d. Let nextArg be IteratorValue(next).
    e. ReturnIfAbrupt(nextArg).
    f. Append nextArg as the last element of list.

결론을 내리자면, Spread Operator로 복사한 객체(배열)은 1depth의 값에서만 깊은 복사를 실행한다.가 된다..!

만약 정말 완전한 깊은 복사를 구현하려면, for문을 이용한 재귀적인 깊은 복사를 구현하거나 JSON으로 stringfy시킨후 다시 parse하는 과정을 거치면 비로소 완전한 참조가 끊기는 깊은 복사가 구현된다. 단, 이 방법의 경우 성능상의 문제가 있는 방법이라고 얘기해서 완벽한 깊은 복사를 구현할 경우 lodash 라이브러리를 사용하는 경우가 많은 것 같았다.


⚠ 잘못된 내용이 있다면 댓글로 알려주심 감사하겠습니다.

0개의 댓글