깊은 복사와 얕은 복사에 대한 심도있는 이야기
1. Array.prototype.slice
- 주로 배열을 깔끔하게 복사할 때 사용할 수 있음.
Array.prototype.slice는 start 부터 end 까지 대상 배열에서 꺼내서
새로운 배열을 만들어 값을 집어 넣음.
start 와 end 가 주어지지 않으면 전체 배열을 복사함!
Array.prototype.slice는 중첩 구조 복사를 제대로 수행할 수 없다 는 단점이 있음.
Array.prototype.slice는 얕은 복사!
2. Spread Operator (펼침 연산자, 전개 연산자)
- 펼침 연산자(Spread Operator)의 등장으로 값의 복사가 전반적으로 매우 편리.
- 펼침 연사자가 호출될 때, 내부적으로는 iterator-looping 액션을 수행.
- 예) 어떤 객체에
[Symbol.iterator] 프로퍼티가 존재한다면 이터러블하다고 할 수 있고 반복문을 돌릴 수 있음
- 만약
const arr = [1, 2, 3]; -> const arrSpread = [...arr]; 이렇게 펼침 연산자를 사용한다면
if (!(Typeof(b) is Iterable)) {
throw TypeError
}
var a = [];
for (var i = 0; i < b.length; i += 1) {
a.push(b[i]);
}
이러한 형식으로 돌아간다. (이거보다 더 훨씬 많은 검사과정이 있겠지만..?)
- 펼침 연산자도 위와 같은 구조로 돌아가기에 중첩 구조는 복사하지 못한다!
3. Object.assign
Object.assign 으로 객체를 복사는 불가능하다.
- 코드 예시 (복사 불가능)
const arr = [1, 2, [3, 4]];
const copied = Object.assign([], arr);
checker(arr, copied);
copied[2].push(5);
checker(arr, copied);
- 심층 복제의 경우
Object.assign ()이 속성 값을 복사하기 때문에 대안을 사용해야 함.
소스 값이 개체에 대한 참조 인 경우 해당 참조 값만 복사함. (MDN의 Object.assign 번역)
4. JSON.parse & JSON.stringify
JSON.stringify 는 중첩 구조를 복사할 수 없는 이터러블 순회를 해결할 수 있다.
(입력 값으로 넘어온 데이터를 문자로 변형을 시켜주는 메소드)
JSON.parse 는 JSON.stringify등으로 변형된 문자를 다시 원래 객체로 되돌려주는 역할을 함.
- 코드 예시
const arr = [1, 2, [3, 4]];
const copied = JSON.parse(JSON.stringify(arr));
checker(arr, copied);
copied[2].push(5);
checker(arr, copied);
- 중첩구조 복사 역시 아주 깔끔하게 수행된 것을 볼 수 있다.
객체 순환을 통해 값을 옮겨담는 과정이 아닌, 문자열로 변경 후
그것을 다시 해석해 원본 객체로 변경하는 과정에서 자바스크립트의 문자열(string)타입이
불변성 형질의 띠는 immutable primitive type (원시타입)이기 때문.
- 코드 예시 - 예외 1 (
Date)
const obj = { d: new Date() };
const copied = JSON.parse(JSON.stringify(obj));
checker(obj, copied);
- Date 객체가
JSON.stringify 의 입력 값으로 전달되면 JSON.stringify는
Date 객체의 toString 메소드를 실행.
같은 시간 같은 날짜를 가리키는 데이터라고 해도 보여지는 방식이 달라졌기 때문에
두 값의 서로 다른 값으로 간주되는 것
- 코드 예시 - 예외 2 (ECMA2020의
BigInt)
JSON.stringify(BigInt(1));
Array.prototype.slice 와 같은 예제에서 보여준 메소드들과는
다르게 JSON.stringify 는 무한 사이클을 갖는 구조를 받지 않음.
const a = [];
a[0] = a;
JSON.stringify(a);
JSON.stringify는..
- JSON 객체에 대한 명세서 따로 존재하는데, ECMA 에서 관리되고 있으며 번호는 404 를 부여받음.
그래서 ECMA-404 라고 통칭한다
- ECMA-404 (JSON 명세서)의 JSON 값으로 표현될 수 있는 종류.
Object, array, number, string, true, false, null
- JSON 값으로 판단될 수 있는건 ECMA-404 에 따르면 위 처럼 7 가지 종류만 포함
나머지는 JSON 으로 분류될 수 없기에 JSON.stringify로 제대로 변환이 안될 수 있다.
이에 관한 내용은 아래 기술문서를 보자!
느낀점
- 음.. 이터러블이랑 Object.assign을 알고나서 또 다시 읽는 것도 좋을 것 같다.
또 알아야 할 것은 자바스크립트의 최신 기능들.
그래도 더 확고히 복사에 대해 이해가 어느정도 되었고, 종은 문서였다.
참고 링크
깊은 복사와 얕은 복사에 대한 심도있는 이야기
1. Array.prototype.slice
Array.prototype.slice는 start 부터 end 까지 대상 배열에서 꺼내서새로운 배열을 만들어 값을 집어 넣음.
start 와 end 가 주어지지 않으면 전체 배열을 복사함!
Array.prototype.slice는 중첩 구조 복사를 제대로 수행할 수 없다 는 단점이 있음.Array.prototype.slice는 얕은 복사!2. Spread Operator (펼침 연산자, 전개 연산자)
[Symbol.iterator]프로퍼티가 존재한다면 이터러블하다고 할 수 있고 반복문을 돌릴 수 있음const arr = [1, 2, 3];->const arrSpread = [...arr];이렇게 펼침 연산자를 사용한다면이러한 형식으로 돌아간다. (이거보다 더 훨씬 많은 검사과정이 있겠지만..?)
3. Object.assign
Object.assign으로 객체를 복사는 불가능하다.Object.assign ()이 속성 값을 복사하기 때문에 대안을 사용해야 함.소스 값이 개체에 대한 참조 인 경우 해당 참조 값만 복사함. (MDN의 Object.assign 번역)
4. JSON.parse & JSON.stringify
JSON.stringify는 중첩 구조를 복사할 수 없는 이터러블 순회를 해결할 수 있다.(입력 값으로 넘어온 데이터를 문자로 변형을 시켜주는 메소드)
JSON.parse는JSON.stringify등으로 변형된 문자를 다시 원래 객체로 되돌려주는 역할을 함.객체 순환을 통해 값을 옮겨담는 과정이 아닌, 문자열로 변경 후
그것을 다시 해석해 원본 객체로 변경하는 과정에서 자바스크립트의 문자열(string)타입이
불변성 형질의 띠는 immutable primitive type (원시타입)이기 때문.
Date)JSON.stringify의 입력 값으로 전달되면JSON.stringify는Date 객체의
toString메소드를 실행.같은 시간 같은 날짜를 가리키는 데이터라고 해도 보여지는 방식이 달라졌기 때문에
두 값의 서로 다른 값으로 간주되는 것
BigInt)Array.prototype.slice와 같은 예제에서 보여준 메소드들과는다르게
JSON.stringify는 무한 사이클을 갖는 구조를 받지 않음.함수 역시
JSON.stringify가 문자로 바꿀 수 없는 객체 중 하나다.JSON.stringify는..그래서 ECMA-404 라고 통칭한다
Object,array,number,string,true,false,null나머지는 JSON 으로 분류될 수 없기에
JSON.stringify로 제대로 변환이 안될 수 있다.이에 관한 내용은 아래 기술문서를 보자!
느낀점
참고 링크