불변 객체 생성과 얕은/깊은 복사

솜주먹·2022년 7월 21일
0

📢안내

  • 개발자를 꿈꾸는 뉴비입니다.
  • 틀린 부분이 있으면 지적 부탁드립니다.



📌 불변 객체 생성

📖 불변 객체

  • 변하지 않는 객체
  • 방법 : const, Object.freeze()

📖 const

  • 변수를 상수로 선언할 수 있다
const immutability = '불변'
immutability = '가변'		// 에러 발생! (TypeError: Assignment to constant variable.)
console.log(immutability)	// 실행되지 않으나 '불변'그대로 저장된 상태
  • 하지만 상수로 선언한 객체는?
  • 객체 재할당은 불가하지만 속성은 변경 가능하다
const immutability = {}
immutability.name = '불변'		
console.log(immutability)	// {name:'불변'}

📖 Object.freeze()

  • 객체의 재할당은 가능하지만, 속성 변경은 불가하다
let immutability = {name: '불변'}
Object.freeze(immutability)
immutability.name = '가변'		// 속성 변경 시도 => 에러 미발생
console.log(immutability)		// {name: '불변'}
immutability = {age: 30}		// 재할당 시도
console.log(immutability)		// {age: '30'}

💬 정리 : 위 두가지 방법을 조합하면 완벽한 불변 객체가 생성된다

const immutability = {name: '불변'}
Object.freeze(immutability)

📌 얕은/깊은 복사

📖 얕은 복사 (shallow copy)

  • 객체를 복사할때 기존 변수의 참조값을 을 복사하는 것
  • 복사후 객체를 수정할 때 같은 참조를 가리키고 있기에 기존 변수에 영향을 끼침
  • 방법 : Array.prototype.slice(), Spread 연산자, Object.assign()

✍ 얕은 복사 예시

  1. Array.prototype.slice()
// 예시 1
let arr1 = [0, 1, 2, 3, 4]
let arr2 = arr1.slice()			// 복사 진행!(주소값)
arr1.push(10)
arr2[0] = 10

console.log(arr1)				// [0,1,2,3,4,10]
console.log(arr2)				// [10,1,2,3,4]
// 예시1만 보면 깊은 복사로 보이지만
// 기본적으로 원시 값은 깊은 복사이기에 기존 배열에 영향을 주지 않는 것이다

// 예시 2
let arr1 = [0, 1, 2, [3, 4]]
let arr2 = arr1.slice()			// 복사 진행!(주소값)
arr1.push(10)
arr2[3][0] = 10

console.log(arr1)				// [0,1,2,[10,4],10]
console.log(arr2)				// [0,1,2,[10,4]]
// 예시2를 확인해보면 중첩 구조(객체, 이중배열 등)는
// 원시 값이 아닌 참조값, 즉 주소값을 가져왔기에 기존 배열에 영향을 주게 된다
  1. Spread 연산자
// 예시 1
let arr1 = [0, 1, 2, 3, 4]
let arr2 = [...arr1]			// 복사 진행!(주소값)
arr1.push(10)
arr2[0] = 10

console.log(arr1)				// [0,1,2,3,4,10]
console.log(arr2)				// [10,1,2,3,4]

// 예시 2
let arr1 = [0, 1, 2, [3, 4]]
let arr2 = [...arr1]			// 복사 진행!(주소값)
arr1.push(10)
arr2[3][0] = 10

console.log(arr1)				// [0,1,2,[10,4],10]
console.log(arr2)				// [0,1,2,[10,4]]
// 스프레드 연산자 역시 동일하다
  1. Object.assign()
let object = {
    name: "솜주먹",
    age: {
        '만나이': 29,
        '나이': 30
    }
};
let copyOb = Object.assign({}, object);	// 복사 진행!
copyOb.age['만나이'] = 500;
console.log(object)				// { name: '솜주먹', age: { '만나이': 500, '나이': 30 } }
console.log(copyOb)				// { name: '솜주먹', age: { '만나이': 500, '나이': 30 } }
// 복사된 객체(copyOb) 자체는 원본(object)와 다른 객체이지만
// 그안에 들어있는 값은 원본과 같은 참조값을 가리키고 있기에 원본에 영향을 줌

📖 깊은 복사 (deep copy)

  • 객체를 복사할때 기존 변수의 실제값을 을 복사하는 것
  • 복사후 객체를 수정하더라도 실제값을 복사했기에 기존 변수에 영향을 끼치지 않음
  • 방법 : JSON.stringify()=>JSON.parse(), 재귀함수, Lodash 라이브러리

✍ 깊은 복사 예시

  1. JSON.stringify()
let object = {
    name: "솜주먹",
    age: {
        '만나이': 29,
        '나이': 30
    },
    friend: [0, 1, 2, [3, 4]]
}
let copyOb = JSON.stringify(object)		// 객체를 JSON형태로 변경, 이때 원본 객체와 모든 참조가 끊어짐
copyOb = JSON.parse(copyOb)				// JSON형태를 다시 JS객체로 변경

copyOb.age['만나이'] = 500;
copyOb.friend[3][0] = 10

console.log(object)		// {name: '솜주먹', age: { '만나이': 29, '나이': 30 }, friend: [ 0, 1, 2, [ 3, 4 ]]}
console.log(copyOb)		// {name: '솜주먹', age: { '만나이': 500, '나이': 30 }, friend: [ 0, 1, 2, [ 10, 4 ]]}

// 해당 방식의 단점
// 1. 쉽고 간단하지만 다른 방법의 깊은 복사에 비해 느리다
// 2. 객체가 function일 경우, undefined로 처리한다

외 다른 예시는 참조의 빵슨 개발 블로그 확인 부탁드립니다!


💖 참조

빵슨 개발 블로그

0개의 댓글