[Achievement Goal]
얕은 복사와 깊은 복사의 개념에 대해서 정확하게 짚고 넘어가자!
이번 얕은복사와 깊은 복사는 정규 수업에서 배운내용은 아니지만
앞으로 심화 자바스크립트를 배움에 있어서 꼭 필요한 내용인것 같아 정리해보았다.
예외적인 형태를 제외하고, 객체에서의 기본적인 쓰임이라고 볼 수 있다.
간단한 예시 두개로 먼저 본 후 설명하겠다.
let coffeeObj = { brand : 'starbucks' , roast : 'kenya' , tasteRate : 5 }
여기 coffeeObj 라는 객체가 있다.
현재 coffeeObj 객체의 키로 brand,roast,tasteRate 총 세가지 밖에 없다.
function coffeeFunc(){
coffeObj['bestMenu'] = 'americano'
return coffeObj;
}
coffeeFunc()
// {brand: "starbucks", roast: "kenya", tasteRate: 5, bestMenu: "americano"}
coffeeFunc() 라는 함수 안에 coffeObj['bestMenu'] = 'americano' 를 추가한 후
리턴하면 bestMenu 라는 키, 값도 추가가 된다.
{brand: "starbucks", roast: "kenya", tasteRate: 5, bestMenu: "americano"}
coffeObj
{brand: "starbucks", roast: "kenya", tasteRate: 5, bestMenu: "americano"}
똑같이 bestMenu : americano 가 추가되었다.
이번에는 새로운 변수에 기존 변수를 재할당 해보았다.
let coffeeObj = { brand : 'starbucks' , roast : 'kenya' , tasteRate : 5 }
똑같은 coffeeObj 라는 객체가 있다.
function coffeeFunc(){
let coffeeObj2 = coffeeObj;
delete coffeeObj2.tasteRate;
return coffeeObj2;
}
coffeeFunc()
// {brand: "starbucks", roast: "kenya"}
coffeeFunc 라는 함수 안에 새로운 변수명인 coffeeObj2 에 coffeeObj 를 할당해주는 식을 세우고,
coffeeObj2 의 tasteRate 키를 지워주었다.
그렇다면 기존의 coffeeObj 객체는 어떻게 되었을까?
coffeeObj
{brand: "starbucks", roast: "kenya"} => 함수식과 마찬가지로 tasteRate 가 사라진 것을 볼 수 있다.
이처럼, 얇은 복사는 기존의 객체가 담겨있는 변수를 또다른 변수에 할당해 주면 그 변수의 움직임에 따라 같이 변한다고 볼 수 있다.
== 데이터가 담긴 주머니가 하나 더 생기는 것이 아니라, 하나의 데이터를 각기 다른 변수에서 공유! 한다고 생각하면 쉬울 것 같다.
하나의 데이터주머니를 다른 변수와 공유하는 얇은 복사와 반대로,
깊은 복사는 변수에 다른 변수를 할당 하면 새로운 객체가 탄생하는 개념이다.
이말인 즉슨, 새로운 변수에 기존 객체를 할당 후 변동이 생겼다 하더라도 기존 변수의 객체에는 아무런 영향이 가지 않는다.
그렇다면 깊은복사는 어떨때 적용될까?
let clothes = {
brand : 'polo',
specialty : 'shirts',
rate : 5
}
let clothes2 = Object.assign({},clothes)
clothes2
// {brand: "polo", specialty: "shirts", rate: 5}
clothes 라는 객체 안에 brand, specialty, rate 라는 세개의 키,값이 존재한다.
그리고 그 값을 Object.assign 메소드를 통해 clothes2 라는 새로운 변수명에 할당해주어서
clothes2 의 객체 값도 clothes 와 동일해졌다.
clothes2.specialty = 'knit'
clothes2
// {brand: "polo", specialty: "knit", rate: 5}
여기서, clothes2 의 specialty 의 밸류값인 shirts 가 마음에 안들어 knit 로 바꿨다.
clothes
{brand: "polo", specialty: "shirts", rate: 5}
하지만 clothes 는 폴로의 스페셜티는 셔츠, 그대로다!
Object.assign 메소드를 사용하여 새로운 값을 복사해줬기 때문이다.
앞서 블로그에서 다룬 spread 연산자에서도 깊은 복사의 형태가 이루어진다.
*짚고 넘어가기
spread 연산자는 배열 / 객체에서 사용 가능하며 함수의 매개변수로 이용 될 수 도 있다.
const person = {name : 'sook', age : '30s'}
const detail = {city : 'seoul', hobby : 'coding'}
const ttl = {...person,...detail}
ttl
// {name : 'sook', age : '30s',city : 'seoul', hobby : 'coding'}
여기 스프레드 연산자로 이루어진 코드가 있다.
person 과 detail 의 객체를 섞어 ttl 의 객체는 {name : 'sook', age : '30s',city : 'seoul', hobby : 'coding'} 가 되었다.
여기서, 취미를 코딩이 아닌 운동하기로 바꿔보겠다..
detail.hobby = 'work out'
detail
// {city: "seoul", hobby: "work out"}
ttl
// {name: "sook", age: "30s", city: "seoul", hobby: "coding"}
detail 의 hobby 를 work out 으로 바꿨음에도 ttl 의 hobby 값은 그대로 coding 이다.
하지만 깊은복사에서 무조건 저 공식이 통하는 것은 아니다.
만약 객체안의 객체, 배열안의 배열 처럼 두번째 이상의 값을 변경할땐 얇은복사가 진행된다.
예제로 살펴보겠다.
let apple = {
selling : {
iPhone : 1 ,
iPad : 3,
airPods : 2
}
}
apple
//selling: {iPhone: 1, iPad: 3, airPods: 2}
let willSell = {...apple}
apple 의 제품들이 담겨있는 객체에, willSell 이라는 새로운 변수를 생성해 스프레드 연산자로 apple 을 새로 복사하였다.
앞서 말한것처럼 willSell 객체에 어떠한 값을 추가 및 삭제해도 apple 에는 아무런 영향도 가지 않는다.
하지만 willSell 안의 또다른 객체인 selling 을 수정하면 어떻게 될까?
willSell['selling']['appleCar'] = 4
willSell
추후 팔게 될 애플카를 넣어보았다. (주가야 올라라.🙏🏻)
{selling:
airPods: 2
appleCar: 4
iPad: 3
iPhone: 1
}
willSell 의 selling 에 애플카도 4위로 추가가 잘 되었다.
그렇다면 기존값이었던 apple 객체의 변화는?
apple
{
selling:
airPods: 2
appleCar: 4
iPad: 3
iPhone: 1
}
스프레드 연산자임에도 객체 안의 객체값이 수정되어 얇은 복사가 진행되었다.
이처럼, Object.assign 을 쓰거나 스프레드 연산자를 쓴다고 해서 모두 깊은 복사가 진행되는것은 아니다.
물론 JSON.stringfy(), 재귀함수, 고차함수를 써서 fix 된 깊은복사를 진행할수도 있겠지만
어디에서, 어떤값을 복사할건지 잘 파악해서 조심히 쓰도록 해야겠다!