개발일기
객체 타입의 얕은 복사와 깊은 복사 본문
1.얕은 복사
복사본의 속성이 복사본이 만들어진 원본 객체와 같은 참조(메모리 내의 같은 값을 가리킴)를 공유하는 복사이다.
var person = {
name: 'Lee'
};
var copy = person;
copy.name = 'Kim'
console.log(person) //{name : 'Kim'}
console.log(copy) //{name : 'Kim'}
따라서 위와 같이 원본이나 복사본을 변경하면, 다른 객체 또한 변경될 수 있다.
2.얕은 복사 방법
1. Array.prototype.slice()
앝은 복사 방법의 대표적인 방법이다. slice() 메서드는 어떤 배열의 begin부터 end 까지 (end 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환한다. 원본 배열은 바뀌지 않는다. 만약 begin부터 end를 설정하지 않는다면, 기존 배열을 전체 복사한다.
const original = ['a',2,true,4,"hi"];
const copy = original.slice();
copy.push(10)
copy[0] = 'c'
console.log(original) //[ 'a', 2, true, 4, 'hi' ]
console.log(copy) //[ 'c', 2, true, 4, 'hi', 10 ]
위의 설명과 같이 copy의 값을 바꾸거나 추가해도 원본 배열은 바뀌지 않는다. 그렇기 때문에 slice()메서드가 깊은 복사로 보일 수 있지만, 원시값을 저장한 1차원 배열일 뿐이다. 원시값은 기본적으로 깊은 복사이다. slice()메서드는 기본적으로 얕은 복사를 수행한다.
const original = [{ name : 'Kim', age : 1},true];
const copy = original.slice();
copy[0].name = 'Lee'
copy[1] = false
console.log(original) // [ { name: 'Lee', age: 1 }, true ]
console.log(copy) // [ { name: 'Lee', age: 1 }, false ]
위와 같이 중첩 구조를 갖는 2차원이면 앝은 복사를 수행하게 된다.
2.Object.assign()
Object.assign() 메서드는 모든 객체들을 복사해 대상 객체에 붙여 넣는다.
const original = {name : {lastName:'Kim', firstName: 'gildong'}, age : 1,}
const copy = Object.assign({},original)
copy.name.lastName = 'Lee'
copy.age = 2
console.log(original) //{ name: { lastName: 'Lee', firstName: 'gildong' }, age: 1 }
console.log(copy) //{ name: { lastName: 'Lee', firstName: 'gildong' }, age: 2 }
위의 메서드도 마찬가지로 1차원 객체일 때는 원본 객체에 영향을 주지 않지만,
2차원 일 경우 얕은 복사를 수행한다.
3. Spread 연산자 (전개 연산자)
const original = {name : {lastName:'Kim', firstName: 'gildong'}, age : 1,}
const copy = {...original}
copy.name.lastName = 'Lee'
copy.age = 2
console.log(original) //{ name: { lastName: 'Lee', firstName: 'gildong' }, age: 1 }
console.log(copy) //{ name: { lastName: 'Lee', firstName: 'gildong' }, age: 2 }
Spread 연산자도 마찬가지로 1차원의 값에서만 깊은 복사가 실행되고,
다차원부터는 얕은 복사가 실행된다.
3. 깊은 복사
복사본의 속성이 복사본이 만들어진 원본 객체와 같은 참조(메모리 내의 같은 값을 가리킴)를 공유하지 않는 복사이다. 따라서 원본이나 복사본을 변경할 때, 다른 객체가 변경되지 않는 것을 보장 할 수 있다.
4.깊은 복사 방법
1.JSON.parse && JSON.stringify
JSON.stringify()는 객체를 json 문자열로 변환하는데 이 과정에서 원본 객체와의 참조가 모두 끊어진다.객체를 json 문자열로 변환 후, JSON.parse()를 이용해 다시 원래 객체로 만들어 준다. 이 방법은 사용하기는 쉽지만 다른 방법에 비해 느리다는 단점이 있다.
const original = { name: { lastName: "Kim", firstName: "gildong" }, age: 1 };
const copy = JSON.parse(JSON.stringify(original))
copy.name.lastName = "Lee"
copy.age = 2
console.log(original) //{ name: { lastName: 'Kim', firstName: 'gildong' }, age: 1 }
console.log(copy) //{ name: { lastName: 'Lee', firstName: 'gildong' }, age: 2 }
위와 같이 복사본의 1차원, 2차원의 값을 바꿔도 원본 값에 아무런 영향을 주지 않는다.
2. 재귀 함수
재귀 함수란 정의 단계에서 자신을 재참조하는 함수를 말한다. 함수 안에서 함수를 반복적으로 사용하여 새로운 object를 반환한다.복잡하다는 단점이 있다.
const object = { name: { lastName: "Kim", firstName: "gildong" }, age: 1 };
const copyFn = (object) => {
if(object === null || typeof object !== "object"){
return object;
}
const copy = Array.isArray(object) ? [] : {};
for(let key of Object.keys(object)){
copy[key] = copyFn(object[key]);
}
return copy;
}
const copy = copyFn(object);
copy.name.lastName = 'Lee'
copy.age = 2
console.log(object) //{ name: { lastName: 'Kim', firstName: 'gildong' }, age: 1 }
console.log(copy) //{ name: { lastName: 'Lee', firstName: 'gildong' }, age: 2 }
위와 같이 복사본의 1차원, 2차원의 값을 바꿔도 원본 값에 아무런 영향을 주지 않는 깊은 복사가 실행 된다.
3.Lodash 라이브러리 사용
라이브러리를 사용하면 더 쉽고 안전하게 깊은 복사를 할 수 있다.
const deepCopy = require("lodash.clonedeep")
const object = { name: { lastName: "Kim", firstName: "gildong" }, age: 1 };
const copy = deepCopy(object);
copy.name.lastName = 'Lee'
copy.age = 2
console.log(object) //{ name: { lastName: 'Kim', firstName: 'gildong' }, age: 1 }
console.log(copy) //{ name: { lastName: 'Lee', firstName: 'gildong' }, age: 2 }
도움받은 블로그 : https://bbangson.tistory.com/78
'Javascript' 카테고리의 다른 글
함수 호이스팅 (0) | 2024.07.18 |
---|---|
메서드 기록해두기(split, slice, splice) (0) | 2024.06.10 |
자바스크립트 구조분해할당 (0) | 2024.03.31 |
원시타입과 객체타입 (0) | 2024.03.06 |
var와 let 그리고 호이스팅 (1) | 2024.03.01 |