[JS] Shallow Copy & Deep Copy

장여진·2022년 3월 19일
0

값 복사

값을 복사하는 경우 새로운 변수에 값을 대입해주면 기존 변수는 원본이 되고 새로운 변수는 복사본이 되어 복사본을 변경하여도 원본이 변경되지 않는다.
예시)

const aaa = "철수"

let bbb = aaa

console.log(bbb) //철수

bbb = "영희"
console.log(bbb) //유리
console.log(aaa) //철수

이렇게 값을 복사하는 방식은 객체와 배열 복사에 적용되지 않는다.

예시)

let profile1 ={
  name:"철수",
  age:8,
  school:"다람쥐초등학교"
}

console.log(profile1)let profile2 = profile1
console.log(profile2) //{ name: '철수', age: 8, school: '다람쥐초등학교' }
profile2.name = "영희"
console.log(profile2)//{ name: '유리', age: 8, school: '다람쥐초등학교' }

console.log(profile1)//{ name: '유리', age: 8, school: '다람쥐초등학교' }

profile1.age =10
console.log(profile1) //{ name: '유리', age: 10, school: '다람쥐초등학교' }
console.log(profile2) //{ name: '유리', age: 10, school: '다람쥐초등학교' }

=> 객체와 배열을 값 자체를 가지고 있는 것이 아니라 값이 들어 있는 주소를 가지고 있어서 주소가 복사되는 것이다!!!

이러한 문제를 해결하기 위해 Shallow Copy(얕은 복사),Deep Copy(깊은 복사)을 이용할 수 있다

Shallow copy

SpreadOperator방식을 이용한 복사 => ...복사할 객체명

const child1 = {
  name:"철수",
  age:13,
  school:"다람쥐초등학교"
}

let child2 = { ...child1 }  // SpreadOperator 사용

console.log(child1) // { name: '철수', age: 13, school: '다람쥐초등학교' }
console.log(child2) // { name: '철수', age: 13, school: '다람쥐초등학교' }

child2.age =23

console.log(child1) // { name: '철수', age: 13, school: '다람쥐초등학교' }
console.log(child2) // { name: '철수', age: 23, school: '다람쥐초등학교' }

//배열 복사
배열의 복사
const aaa = ["철수","영희",]
const bbb = [ ...aaa] // SpreadOperator 사용

const ccc = ["철수","영희","유리]
const ddd =["수지","맹구"]

const eee = [...ccc,...ddd] // SpreadOperator 사용

복사한 child2의 age을 변경하여도 child1의 age는 변경되지 않는 것을 볼 수 있다.
하지만!!! SpreadOperator를 이용한 복사 방식은 얕은 복사로 한계가 있다.

const child1 = {
  name:"철수",
  age:13,
  school:"다람쥐초등학교"
    hobby: {
  	frist:"게임",
  	second:"운동"
  }  
}
let child2 = { ...child1 }

child2.hobby.frist = "독서"

console.log(child2) // {name: '철수',age: 13,school: '다람쥐초등학교',hobby: { frist: '독서', second: '운동' }}
console.log(child1) // {name: '철수',age: 13,school: '다람쥐초등학교',hobby: { frist: '독서', second: '운동' }}

hobby안의 내용을 변경하면 원본도 변경된다..
이는 hobby도 객체이기 때문에 값이 들어온 것이 아니라 hobby의 주소값이 들어온 것이다.
깊은 복사까지는 SpreadOperator로 가능하지 않기 때문에 얕은 복사라고 하는 것이다.

이를 보완하기 위한 방식으로 객체를 문자열로 변경하여 복사해주는 방식이 있다.

Deep copy

JSON.stringfiy(객체명)을 사용하면 객체를 문자열로 변경가능하다.
객체를 문자열로 변경 후 대입을 하고 나면 다시 객체화를 하는 과정이 필요하다.
이는 JSON.parse(문자열)로 가능하다.

const child1 = {
  name:{ first:"김",last:"철수"},
  age:13,
  school:"다람쥐초등학교"
}

JSON.stringify(child1)
let child2 =JSON.parse(JSON.stringify(child1))

console.log(child2)

child2.name.first = "이"
child2.name.last = "유리"

console.log(child2) // {name: { first: '이', last: '유리' },age: 13,school: '다람쥐초등학교'}
console.log(child1) // {name: { first: '김', last: '철수' },age: 13,school: '다람쥐초등학교'}

복사본 child2의 name을 변경해도 child1의 값이 변경되지 않는 것을 볼 수 있다!

*** 주의!!! Deep copy는 성능이 좋지 못해서 보통 Shallow copy를 사용!!!

*** Deep copy의 단점을 보완하기 위해 lodash라는 라이브러리를 사용할 수 있음!

REST파라미터

구조분해할당의 심화 내용
실무에서 원본 자체 변경은 좋지않음(새롭게 하나 더 생성 후 수정이 좋음)
restParameter는 기존 배열의 일부만 복사하고 싶을 때 유용한 방식 => ...rest


const child ={
  name:"철수",
  age:8,
  school:"다람쥐초등학교",
  money:2000,
  hobby:"게임"
}

const {money, hobby, ...rest} =child //restParameter
//새롭게 만들 객체에서 제외될 변수를 먼저 선언 후 나머지는 rest라는 객체에 대입하는 것


console.log(rest) // { name: '철수', age: 8, school: '다람쥐초등학교' }


const {school, ...aaa} = child
console.log(aaa)   // { name: '철수', age: 8, money: 2000, hobby: '게임' }

// ...뒤에는 새로 생성될 객체의 이름으로 원하는 객체명을 넣을 수 있음

공부하며 작성하고 있는 블로그입니다.
잘못된 내용이 있을 수 있으며 혹시 있다면 댓글 달아주시면 감사하겠습니다 😊

0개의 댓글