javascript에서 shallow copy(얕은 복사), deep copy(깊은 복사)에 대해 알아본다.
배열의 얕은 복사
array.slice()
객체의 얕은 복사obj.object(target, source)
깊은 복사JSON.stringify
JSON.parse
// 배열 복사 : 참조 복사
const arrayA = [1, 2, 3, 4, 5];
const arrayB = arrayA; // 참조값 복사
console.log(arrayA === arrayB); // true, 참조하고 있는 값이 같기 때문에
arrayB[2] = 10;
console.log(arrayA); // [1, 2, 10, 4, 5]
console.log(arrayB); // [1, 2, 10, 4, 5]
// 같은 값을 참조하고 있기 때문에 arrayB를 수정했을 때 arrayA가 바라보고 있는 값도 수정되어있음.
const arrayC = [1, 2, 3, 4, 5];
const arrayD = arrayC.slice(); // 복사
console.log(arrayC === arrayD); // false
// slice로 복사본을 만들었기 때문에 두 배열이 참조하고 있는 값은 다름.
arrayD[2] = 10;
console.log(arrayC); // [1, 2, 3, 4, 5]
console.log(arrayD); // [1, 2, 10, 4, 5]
// 복사본을 수정했기 때문에 원본의 수정은 없음.
const arrayK = [1, 2, 3, 4, 5];
const arrayQ = [...arrayK]
console.log(arrayK === arrayQ); // false
// 복사본을 만들었기 때문에 두 배열이 참조하고 있는 값은 다름.
arrayQ[2] = 10;
console.log(arrayK); // [1, 2, 3, 4, 5]
console.log(arrayQ); // [1, 2, 10, 4, 5]
const objA = { class: "user", info: { id: "ABC", age: "30" } };
const objB = Object.assign({}, objA);
console.log(objA === objB); // false
console.log(objA.info === objB.info); // true
// 배열과 마찬가지로 얕은 복사 시, 참조값은 참조 주소를 복사하는 문제
const objW = { class: "user", info: { id: "ABC", age: "30" } };
const objP = {...objW}
console.log(objW === objP); // false
objP['class'] = 'admin';
console.log(objW.class === objP.class); // false
console.log(objW.class); // user
console.log(objP.class); // admin
objP.info.id = "PQW";
console.log(objW.info === objP.info); // true
console.log(objW.info.id === objP.info.id); // true
console.log(objW.info.id); // PQW
console.log(objP.info.id); // PQW
위와 같은 방법으로 복사할 경우,
원시값
은 새로운 값이 할당되지만
Array
나Object
와 같은 참조값의 경우, 참조값이 복사되기 때문에
복사한 값을 수정할 경우 원본도 함께 수정됨.
물론 이를 의도한 경우 문제가 되지 않음
const arrayE = [1, 2, 3, 4, 5, [100, 200], { name: "kim" }];
const arrayF = arrayE.slice();
console.log(arrayE === arrayF); // false
// 원시값의 경우 새로운 값을 할당하지만
console.log(arrayE[5] === arrayF[5]); // true
console.log(arrayE[6] === arrayF[6]); // true
// array나 object와 같은 참조값의 경우 참조주소를 복사
arrayE[5][1] = 300;
console.log(arrayE[5]); // 300
console.log(arrayF[5]); // 300
arrayE[6][name] = "lee";
console.log(arrayE[6][name]); // lee
console.log(arrayF[6][name]); // lee
JSON 형식으로 변환했다가 다시 parse하는 방식으로 완전히 새로운 값을 할당함.
const arrayG = [1, 2, 3, 4, 5, [100, 200], { name: "kim" }];
const arrayH = JSON.parse(JSON.stringify(arrayG));
console.log(arrayG === arrayH); // false
console.log(arrayG[5] === arrayH[5]); // false
console.log(arrayG[6] === arrayH[6]); // false
// 완전히 새로운 값을 할당
// 과정 이해
const process1 = JSON.stringify(arrayG); // JSON type으로 변형(String)
console.log(process1); // "[1,2,3,4,5,[100,200],{"name":"kim"}]"
const process2 = JSON.parse(process1); // JSON parse을 통해 javascript 데이터 타입으로 변형
console.log(process2); // [1, 2, 3, 4, 5, [100, 200], { name: "kim" }]
JSON.stringify는 function를 처리하지 못함.
const objC = {
func: function () {
console.log("err");
},
};
const objD = JSON.parse(JSON.stringify(objC));
console.log(objC); // {func: ƒ}
console.log(objD); // {}
// 과정 이해
const process1 = JSON.stringify(objC); // JSON type으로 변형(String)
console.log(process1); // {}
const process2 = JSON.parse(process1); // {}
console.log(process2); // {}
이미 잘 만들어진 라이브러리를 활용함.
const jQueryClone = $.extend(true, {}, obj); // jQuery
const lodashClone = _.cloneDeep(obj); // lodash
댓글 환영
질문 환영
by.protect-me