Immutability (불변성) 포스팅 리스트

- Immutability (불변성) 에 대한 정리- 1

- Immutability (불변성) 에 대한 정리 - 2

- Immutability (불변성) 에 대한 정리 - 3

서두

지난 포스트 ( Immutability (불변성)에 대한 고찰 - 1 )  에서 immutability란 무엇인가? let 그리고 const에 대해 무엇인가? Data TypePrimitive Type과 Object Type에 대해서 알아보았습니다.

 

이번 2편 포스팅에서는 Object Type에서 불변성을 가지려면 어떻게 할 수 있는지에 대해 생각해보는 시간을 가지도록 하겠습니다.

 

Object.assign

immutability (불변성) 은 원본 데이터를 건드리지 않아야 합니다.

그래서 객체를 대입하여 데이터를 쓰고 싶다고 할 때 대표적으로 javascript 내장 객체 함수인 Object.assign 함수가 있습니다.

 

Object.assign(target, ...sources)

이러한 방식으로 구문 방식으로 되어 있으며

첫 번째 매개변수 target : 목표 객체, 객체의 속성을 복사해 반영한 후 반환할 객체.

두 번째 매개변수 sources: 출처 객체, 목표 객체에 반영하고자 하는 속성들을 갖고 있는 객체

 

반환 값: target

var o1 = { name: "kim" }


Object.assign({})

 


Object.assign({}, o1)


const o2 = Object.assign({}, o1)


o2.name = "lee"


const o1 = { name: "kim" };
const o2 = Object.assign({}, o1);

o2.name = "lee";

// 원본에 영향을 주지 않는다.
console.log(o1, o2, o1 === o2);

 

o1에 name: kim이라는 객체를 만들고

o2에 Object.assign을 통해 빈 객체에 복사하는 방식으로 데이터를 만들고 o2에 대입을 시켜줬습니다 ( 자세한 건 그림 참고 )

 

그리고 o2의 객체 속성인 name의 이름을 Lee라고 바꿔줬습니다.

전 포스팅에서 객체끼리 대입하여 데이터를 변경할 때 와는 다르게 동작되고 있습니다.

원본 데이터를 건드리지 않는다는 것입니다.

 

Object.assign의 한계, Nested Object

하지만 이렇게 했지만 Nested Object (중첩 객체)복사가 되지 않습니다.

즉 깊은 복사가 되지 않는다는 것인데 일단 예시를 보겠습니다.

 

 


Object.assign({})


Object.assign({}, o1)



const o2 = Object.assign({}, o1);

 


o2.name = "lee";


o2.score.push(3);

const o1 = { name: "kim", score: [1, 2] };
const o2 = Object.assign({}, o1);

o2.name = "lee";
o2.score.push(3);

console.log(o1);					// { name: 'kim', score: [1, 2, 3]}
console.log(o2);					// { name: 'lee', score: [1, 2, 3]}
console.log(o1 === o2);				// false
console.log(o1.score === o2.score);	// true

 

o1 객체에 score 객체를 추가로 넣어줍니다.

그리고 o2 변수를 만들고 Object.assign 함수를 사용하여 객체 복사를 합니다.

 

하지만 첫 depth(깊이)만 복사되고 Nested Object 중첩 객체는 복사되지 않고 주소가 들어가게 됩니다.

o1 객체의 score와 o2 객체의 score같은 객체를 가리키게 됩니다.

그렇기 때문에 o2.score.push(3)을 하게 되면 o2의 score 데이터가 [1 ,2 ,3] 이 되고 o1 score 데이터 역시 [1, 2, 3] 이 됩니다.

 

그래서 o1과 o2를 비교하면 false가 나오지만 o1.score과 o2.score을 비교하게 되면 true가 나옵니다.

 

Object.assign의 한계, Nested Object 해결법

이렇게 Nested Object 중첩 객체를 복사하기 위해 간단한 방법이 하나 있습니다. ( 중첩 객체를 복사하기 위해선 여러 개가 있지만 이번 포스팅에선 concat을 사용하겠습니다)

그것은 Array.prototype.concat 함수를 사용하는 것입니다.

 

Array.concat([value1[, value2, ...[, valueN]]])

concat은 메서드를 호출한 배열 뒤에 각 인수를 순서대로 붙여 새로운 배열로 만듭니다.

그리고 새로운 배열을 만들어 인자를 추가하여 복제한 배열리턴하는 방식입니다.

하지만 인자가 없다면 새로운 배열복제만 하여 리턴하게 됩니다.

 


o2.score = o2.score.concat()


o2.score.push(3)

var o1 = { name: "kim", score: [1, 2] };
var o2 = Object.assign({}, o1);

o2.name = 'lee';
o2.score = o2.score.concat();
o2.score.push(3);

console.log(o1);					// { name: 'kim', score: [1, 2, 3]}
console.log(o2);					// { name: 'lee', score: [1, 2, 3]}
console.log(o1 === o2);				// false
console.log(o1.score === o2.score);	// false

아까와 같은 방식으로 Object.assign 함수를 사용하여 o1 객체를 복사해서 o2 변수에 넣어줍니다.

그리고 o2.name을 바꾸고 이번엔 o2.score.concat() 하여 배열을 새로운 배열로 만들어 복제하여 o2.score대입하여 줍니다.

그 뒤 o2.score.push(3)을 하게 되면 o1, o2의 score 객체는 서로 다르기 때문에 o1.score의 원본 객체

변하지 않습니다. 

 

왜 Concat을 사용하는가?

왜 concat을 사용하는가에 대한 의문이 들 수도 있습니다.

Object.assign 함수를 사용하면 되는데 왜 굳이 concat 함수를 사용하는 것인가 에 대한 질문에 대하여 설명을 하자면 Object.assign을 사용하게 되면 배열에서 객체가 되기 때문에 배열 고유의 함수들을 사용하고 배열로 쓸려면 Array.prototype.concat()을 사용해야 합니다.

 

이번 포스팅에선 객체를 대입할 때 어떻게 하면 깊은 복사를 하여 immutability (불변성)을 유지하며 Object.assign 함수를 쓰며, 또한 그 함수 (Object.assign)를 쓰더라도 Nested Object 일 경우엔 concat 함수를 써야 된다는 부분에 대해 알아보았습니다.

 

다음 포스팅에선 함수로 객체를 넘길 때 생기는 문제점에 대해 알아보고 시간이 남는다면 Object freeze에 대해서도 알아보겠습니다.

 

그림으로 설명할려고 만들었는데 만들다 보니.. 이렇게 커지게 되네요 ㅋㅋㅋㅋㅋ

 

긴 글 읽어 주셔서 감사합니다.

 

+ Recent posts