mutate는 변화, mutable은 변화 가능한, mutability는 변화 가능성을 의미하는 단어입니다.
불변성(immutability)
자바스크립트에서 불변성이란 객체가 생성된 이후 그 상태를 변경할 수 없는 것을 의미합니다.
여기서 상태를 변경할 수 있는 것과 값을 재할당하는 것은 다르다는 것을 알아야합니다.
let a = 10;
let b = a;
a = 20;
console.log(a,b); // 20 10
위의 코드는 a에 10을 할당하고 b를 a가 가리키는 메모리 주소를 가리키게 합니다.
이때 a의 값을 20으로 변경시켜줍니다.
만약 값을 직접 변경하는 것이라면 a와 b가 둘다 20을 출력해야합니다.
하지만 자바스크립트에서 Number값은 불변성을 유지하기 때문에 새롭게 20이라는 값을 가지는 메모리 주소를 a에 할당하기 때문에 위와 같은 결과가 나오게 됩니다.

자바스크립트에서는 불변성을 유지하는 값들과 그렇지 않은 값들이 나누어져 있습니다.
Bolean, Number, String, Null, undefined, Symbol과 같은 타입들은 불변성을 유지하는 타입들이고 Object타입들은 변경가능한 값들입니다.
이말은 객체는 객체 내부의 값을 변경하면 객체를 참조하고 있는 다른 값들도 다 같이 변경된다는 의미 입니다.
var obj = {
name: 'voler',
}
var new_obj = obj;
obj.name = 'hello';
console.log(obj.name,new_obj.name); // 'hello' 'hello'
위와 같이 coke의 name 값을 변경하였는데 new_coke의 name까지 한번에 변경된 것을 볼 수 있습니다.
Number,String, Boolean, Null, Undefined, Symbol이 있습니다.Object, Array, Function이 있습니다.var v1 = 1;
var v2 = 1;
console.log(v1 === v2) // true
var obj1 = {
name:'voler'
}
var obj2 = {
name:'voler'
}
console.log(obj1 === obj2) // false
var obj1 = { name: 'voler' }
var obj2 = Object.assign({}, obj1)
obj2.name = 'hello'
console.log(obj1.name); // 'voler'
console.log(obj2.name); // 'hello'
// obj1의 불변성은 유지됩니다.
var obj1 = { name: 'voler' }
Object.freeze(obj1)
obj1.name = 'hello'
console.log(obj1) // voler
// 속성 값이 변경되지 않습니다.
var obj1 = { name: 'voler', score: [1, 2] }
var obj2 = Object.assign({}, obj1)
obj2.score = obj2.score.concat() // score Array의 불변성이 유지된다.
obj2.score.push(3)
console.log(obj1) // {name:'voler', score:[1,2]}
console.log(obj2) // {name:'voler', score:[1,2,3]}
var obj = {
name: 'voler'
}
var new_obj = {...obj};
obj.name = 'hello';
console.log(obj.name,new_obj.name); // 'voler' 'hello'
스프레드 문법을 사용하여 객체를 복사하면 객체의 불변성을 유지 할 수 있습니다.
하지만 스프레드 문법은 1레벨 깊이에서만 유효하게 동작하기 때문에 객체 내부의 객체의 불변성까지는 유지 할 수 없습니다.
var obj = {
name: 'voler'
fake:{
name:'hello'
}
var new_obj = {...obj};
obj.fake.name = 'velog';
console.log(obj.fake.name , new_obj.fake.name);
// 'velog' 'velog'
}
만약 레벨 2 객체까지 불변성을 유지해주려면 아래와 같이 별도의 변수에 값을 재할당 하고 넣어주는 번거로운 과정을 거쳐야 합니다.
const obj = {
name: 'voler'
fake:{
name: 'hello'
}
const new_fake = {...obj.fake};
const new_obj = {...obj};
new_obj.fake = new_fake;
obj.fake.name = 'velog';
console.log(obj.fake.name , new_obj.fake.name);
// 'velog' , 'hello'
}
불변성을 유지하기 위해 복잡한 과정 없이 immer 라이브러리를 사용하여 간단하게 불변성을 유지 할 수있씁니다.
npm install immerimport produce from 'immer'import produce from 'immer';
const obj = {
name:'voler'
fake:{
name:'hello'
}
}
const new_obj = produce(obj, (element) => {
element.name = 'velog';
element.fake.name = 'web';
})
console.log(obj.name , new_obj.name); // 'voler' 'velog'
console.log(obj.fake.name , new_obj.fake.name); 'hello' 'web'
HTML spec에서는 'structuredClone()' 이라는 깊은 복사를 위한 글로벌 메서드를 제공하고 있습니다. 이 메서드의 기본 문법은 다음과 같습니다
structuredClone(value)
structuredClone(value, { transfer })
| Parameter | Description |
|---|---|
| value | 복사할 원본 객체 |
| transfer | An array of transferable objects in value that will be moved rather than cloned to the returned object. |
기본적인 사용법입니다
const obj = {
name:'voler'
fake:{
name:'hello'
}
}
const new_obj = structuredClone(obj);
new_obj.fake.name = bye;
console.log(obj) // { name : "voler" , fake { name:"hello" }}
console.log(new_obj) // { name : "voler" , fake { name:"bye" }}
간단하게 사용할 수 있는 메서드인것 같습니다.
최근에 거의 대부분의 브라우저에서 지원을 하기 시작하였다니 잔뜩 쓸 수 있을것 같다.
사용 해 본적은 없지만 structuredClone()을 알게되었을 때 lodash 또한 알게 되었습니다.
불변성을 위해 깊은 복사를 지원하는 메서드이기에 추가하게 되었습니다. 객체 깊은복사 외에 다른 메서드들이 많아서 한번 정리 , 공부를 해봐야 될 것 같다.
클론딥 메서드의 기본 문법은 다음과 같습니다.
_.cloneDeep(value)
직관적으로 보기도 좋고 깔끔하고 사용하기 쉬운 메서드인것 같다.
사용예시
const _ = require('lodash');
const obj = {
name:'voler'
fake:{
name:'hello'
}
}
const new_obj = _.clondeDeep(obj);
new_obj.fake.name = bye;
console.log(obj) // { name : "voler" , fake { name:"hello" }}
console.log(new_obj) // { name : "voler" , fake { name:"bye" }}
출처 : co_mong.log
출처 : Serzhul`s Blog
출처 : geeksforgeeks