μλ°μ€ν¬λ¦½νΈμμ λΆλ³ κ°μ²΄(Immutable Object)λ ν λ² μμ±λ νμλ κ·Έ μνλ₯Ό λ³κ²½ν μ μλ κ°μ²΄λ₯Ό μλ―Έν©λλ€. μ¦, κ°μ²΄ λ΄λΆμ κ°μ΄λ μνκ° λ³κ²½λμ§ μμμ 보μ₯νλ κ°μ²΄μ λλ€. λΆλ³μ±μ νλ‘κ·Έλλ°μμ μ€μν κ°λ μΌλ‘, νΉν ν¨μν νλ‘κ·Έλλ°μμ κ°μ‘°λ©λλ€.
- μμΈ‘ κ°λ₯μ±(Predictability): κ°μ²΄κ° λ³κ²½λμ§ μκΈ° λλ¬Έμ, μ½λμ λ€λ₯Έ λΆλΆμμ μκΈ°μΉ μμ λ³κ²½μ΄ μΌμ΄λ κ±±μ μμ΄ κ°μ²΄λ₯Ό μμ μκ² μ¬μ©ν μ μμ΅λλ€.
- λ³κ²½ μΆμ (Change Detection): λΆλ³ κ°μ²΄λ μλ‘μ΄ μνλ₯Ό λ§λ€ λλ§λ€ μλ‘μ΄ κ°μ²΄λ₯Ό μμ±νλ―λ‘, μ°Έμ‘° λΉκ΅λ₯Ό ν΅ν΄ μ½κ² λ³κ²½ μ¬λΆλ₯Ό κ°μ§ν μ μμ΅λλ€.
- λ©ν°μ€λ λ νκ²½(Thread Safety): λμμ± νλ‘κ·Έλλ°μμ λΆλ³ κ°μ²΄λ μνκ° λ³κ²½λμ§ μκΈ° λλ¬Έμ λ°μ΄ν° κ²½μ(race condition)μ΄λ λμμ± μ€λ₯λ₯Ό λ°©μ§ν©λλ€.
- ν¨μν νλ‘κ·Έλλ°(Functional Programming): ν¨μν νλ‘κ·Έλλ°μ ν΅μ¬ μ리 μ€ νλλ‘, λΆμμ©(side-effects) μμ΄ νλ‘κ·Έλλ°ν μ μκ² ν©λλ€.
μλ°μ€ν¬λ¦½νΈλ κΈ°λ³Έμ μΌλ‘ λΆλ³ κ°μ²΄λ₯Ό λ΄μ₯νκ³ μμ§ μμ§λ§, λΆλ³μ±μ κ°μ νλ λΌμ΄λΈλ¬λ¦¬(μ: Immutable.js)λ₯Ό μ¬μ©νκ±°λ, Object.freeze(), Object.seal() κ°μ λ΄μ₯ λ©μλλ₯Ό μ¬μ©ν΄μ κ°μ²΄μ λΆλ³μ±μ λΆλΆμ μΌλ‘ μ μ§ν μ μμ΅λλ€.
Copy code
const obj = Object.freeze({ name: 'John' });
obj.name = 'Doe'; // μ΄ λ³κ²½μ 무μλ©λλ€, objλ λΆλ³ κ°μ²΄μ
λλ€.
console.log(obj.name); // 'John'
κ·Έλ¬λ Object.freeze()λ μμ(shallow) λκ²°λ§ μννκΈ° λλ¬Έμ, κ°μ²΄ λ΄λΆμ λ€λ₯Έ κ°μ²΄λ μ¬μ ν λ³κ²½ν μ μμ΅λλ€. μλ²½ν λΆλ³μ±μ μν΄μλ λͺ¨λ λ΄λΆ κ°μ²΄μ λν΄μλ μ¬κ·μ μΌλ‘ λκ²°μ μ μ©ν΄μΌ ν©λλ€.
- μ±λ₯: λΆλ³ κ°μ²΄λ μνκ° λ°λ λλ§λ€ μλ‘μ΄ κ°μ²΄λ₯Ό μμ±ν΄μΌ νλ―λ‘, λ©λͺ¨λ¦¬ μ¬μ©λμ΄ μ¦κ°ν μ μμΌλ©°, κ°λΉμ§ 컬λ μ μ λν λΆλ΄μ΄ μ»€μ§ μ μμ΅λλ€.
- μ¬μΈ΅ λΆλ³μ±(Deep Immutability): μλ°μ€ν¬λ¦½νΈμμ μ¬μΈ΅ λΆλ³ κ°μ²΄λ₯Ό λ§λλ κ²μ κΈ°λ³Έμ μΈ λ°©λ²μΌλ‘λ κΉλ€λ‘μ΅λλ€. λ°λΌμ μμ ν λΆλ³μ±μ ꡬννλ €λ©΄ μΆκ°μ μΈ λΌμ΄λΈλ¬λ¦¬λ 볡μ‘ν λ‘μ§μ΄ νμν μ μμ΅λλ€.
μμ 볡μ¬(Shallow Copy)μ κΉμ 볡μ¬(Deep Copy)λ κ°μ²΄λ₯Ό 볡μ¬ν λ μ¬μ©λλ λ κ°μ§ μ£Όμ λ°©λ²μ λλ€. μ΄λ€μ μ°¨μ΄λ 볡μ¬μ κΉμ΄μ κ΄λ ¨μ΄ μμ΅λλ€.
- μμ λ³΅μ¬ : λ°λ‘ μλ λ¨κ³μ κ°λ§ 볡μ¬ν¨.
- κΉμ λ³΅μ¬ : λ΄λΆμ λͺ¨λ κ°λ€μ νλνλ μ°Ύμμ μ λΆ λ³΅μ¬ν¨.
λ³΅μ¬ ν μ°Έμ‘°κ°μ΄ λ€λ₯΄κΈ°μ κΉμ 볡μ¬κ° μ΄λ£¨μ΄μ§λ€κ³ λ³Ό μ μλ€. νμ§λ§ 2μ°¨μ κ°μ²΄μ κ²½μ° κΉμ 볡μ¬κ° μ΄λ£¨μ΄μ§μ§ μλλ€.
// 1μ°¨μ κ°μ²΄
const obj = { a: 1 };
const newObj = Object.assign({}, obj);
newObj.a = 2;
console.log(obj); // { a: 1 }
console.log(obj === newObj); // false
// 2μ°¨μ κ°μ²΄
const obj = {
a: 1,
b: {
c: 2,
},
};
const newObj = Object.assign({}, obj);
newObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 3 } }
λ§μ°¬κ°μ§λ‘ 2μ°¨μ κ°μ²΄μμ κΉμ 볡μ¬κ° μ΄λ£¨μ΄μ§μ§ μλλ€.
const obj = {
a: 1,
b: {
c: 2,
},
};
const newObj = { ...obj };
newObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 3 } }
console.log(obj.b.c === newObj.b.c); // true
2μ°¨μ κ°μ²΄μμ κΉμ 볡μ¬κ° μ΄λ£¨μ΄μ§λ€. νμ§λ§ ν¨μλ₯Ό λ§λ κ²½μ° undefined
λ‘ μ²λ¦¬νλ€.
const obj = {
a: 1,
b: {
c: 2,
},
};
const newObj = JSON.parse(JSON.stringify(obj));
newObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 2 } }
console.log(obj.b.c === newObj.b.c); // false
const obj = {
a: 1,
b: {
c: 2,
},
func: function () {
return this.a;
},
};
const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj.func); // undefined
κ°μ²΄μ κΉμ 볡μ¬λ₯Ό λ€λ₯Έ λ¬Έμ μμ΄ νλ €λ©΄, μ¬κ· ν¨μλ₯Ό μ΄μ©νλ κ²μ΄ μ’λ€.
function deepCopy(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
let copy = {};
for (let key in obj) {
copy[key] = deepCopy(obj[key]);
}
return copy;
}
const obj = {
a: 1,
b: {
c: 2,
},
func: function () {
return this.a;
},
};
const newObj = deepCopy(obj);
newObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 2 }, func: [Function: func] }
console.log(obj.b.c === newObj.b.c); // false
lodash λͺ¨λμ cloneDeep() λ©μλλ₯Ό νμ©ν΄μ, κ°μ²΄μ κΉμ 볡μ¬λ₯Ό ν μ μλ€.
const lodash = require("lodash");
const obj = {
a: 1,
b: {
c: 2,
},
func: function () {
return this.a;
},
};
const newObj = lodash.cloneDeep(obj);
newObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 2 }, func: [Function: func] }
console.log(obj.b.c === newObj.b.c); // false