์๋ฐ์คํฌ๋ฆฝํธ์์ Immutable Object(๋ถ๋ณ ๊ฐ์ฒด)๋ ์ฑ๋ฅ ํฅ์๊ณผ ์์ธก ๊ฐ๋ฅํ ์ฝ๋ ์์ฑ์ ์ํด ์ค์ํ ๊ฐ๋
์
๋๋ค. ์ด ๊ธ์์๋ ๋ถ๋ณ ๊ฐ์ฒด์ ์ ์์ ํ์์ฑ, ์์ฑ ๋ฐฉ๋ฒ ๋ฑ์ ์์ธํ ๋ค๋ฃน๋๋ค.
Object.freeze(), Object.seal(), Object.preventExtensions() ๋ฑ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ๋ถ๋ณ ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ค์ ์์ ์ ํจ๊ป ์์๋ณด์ธ์. ์ด ๊ธ์ ํตํด ๋ถ๋ณ ๊ฐ์ฒด์ ์ฅ์ ์ ์ดํดํ๊ณ , ์ฝ๋์ ์์ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์ด๋ ๋ฐ ๋์์ด ๋๊ธธ ๋ฐ๋๋๋ค.
โฃ ๋ชฉ์ฐจ
์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด์ ๊ดํ ๋ด์ฉ์ ์๋ ํฌ์คํ
์ ์ฐธ๊ณ ํด ์ฃผ์ธ์๐
01. Immutable Object๋ ๋ฌด์์ธ๊ฐ?๐ค
Immutable Object(๋ถ๋ณ ๊ฐ์ฒด)๋ ์์ฑ ํ์ ๊ทธ ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ ๊ฐ์ฒด๋ฅผ ์๋ฏธํฉ๋๋ค. ์ด๋ฌํ ๊ฐ์ฒด๋ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฏ๋ก, ๋ณต์กํ ์ํ ๊ด๋ฆฌ๊ฐ ํ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋งค์ฐ ์ ์ฉํฉ๋๋ค. ๋ณํ์ง ์๋ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๋์ ์์ธก ๊ฐ๋ฅ์ฑ์ด ๋์์ง๊ณ , ์ฌ๋ฌ ๊ฐ์ง ๋ถ์์ฉ(side effects)์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
02. ์ Immutable Object๋ฅผ ์ฌ์ฉํด์ผ ํ๋๊ฐ?๐ก
์ฑ๋ฅ ํฅ์: ๋ถ๋ณ ๊ฐ์ฒด๋ ๋ณต์ฌ๋ณธ์ ์์ฑํ๋ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝ์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์, ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์์ ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ์ ์ต๋๋ค.
์์ธก ๊ฐ๋ฅ์ฑ: ๋ถ๋ณ ๊ฐ์ฒด๋ ๊ทธ ์ํ๊ฐ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฏ๋ก, ์ํ ๋ณํ๋ฅผ ์ถ์ ํ๊ธฐ๊ฐ ์ฝ์ต๋๋ค. ์ด๋ ๋๋ฒ๊น
๊ณผ ์ ์ง ๋ณด์๋ฅผ ๋ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
๋๋ฒ๊น ์ฉ์ด์ฑ: ๋ถ๋ณ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ด ๋ฐ์ํ์ง ์๊ธฐ ๋๋ฌธ์, ์ํ ๋ณํ๋ก ์ธํ ๋ฒ๊ทธ๋ฅผ ์ค์ผ ์ ์์ต๋๋ค.
03. Immutable Object ๋ง๋๋ ๋ฐฉ๋ฒ๐
Object.freeze() ์ฌ์ฉํ๊ธฐ
์๋ฐ์คํฌ๋ฆฝํธ ๋ด์ฅ ํจ์์ธ Object.freeze()๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด๋ฅผ ๋๊ฒฐ(freeze)์ํฌ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ๋๊ฒฐ๋ ๊ฐ์ฒด๋ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค.
const student = {
name: "Alice",
year: 2002,
get age() {
return new Date().getFullYear() - this.year;
},
set age(age) {
this.year = new Date().getFullYear() - age;
},
};
Object.freeze(student);
student.name = "Bob"; // ๋ณ๊ฒฝ๋์ง ์์
console.log(student.name); // "Alice"
Immutable.js ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ
Facebook์์ ๊ฐ๋ฐํ Immutable.js ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ถ๋ณ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ ๋ค๋ฃฐ ์ ์๋๋ก ๋์์ค๋๋ค. Immutable.js๋ฅผ ์ฌ์ฉํ๋ฉด ๋์ฑ ๊ฐ๋ ฅํ ๋ถ๋ณ์ฑ ๊ธฐ๋ฅ์ ํ์ฉํ ์ ์์ต๋๋ค.
const { Map } = require('immutable');
let map1 = Map({ name: "John" });
let map2 = map1.set("name", "Doe");
console.log(map1.get("name")); // "John"
console.log(map2.get("name")); // "Doe"
04. ๋ถ๋ณ ๊ฐ์ฒด์ ๊ฐ๋ณ ๊ฐ์ฒด์ ์ฐจ์ด์ ๐
๋ถ๋ณ ๊ฐ์ฒด์ ํน์ง
- ์์ฑ ์ดํ ์ํ ๋ณ๊ฒฝ ๋ถ๊ฐ
- ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ ๋๋ ํญ์ ์๋ก์ด ๊ฐ์ฒด ์์ฑ
๊ฐ๋ณ ๊ฐ์ฒด์ ๋ฌธ์ ์
- ์ํ ๋ณํ ์ถ์ ์ด๋ ค์
- ๋๋ฒ๊น ์ ํผ๋ ๋ฐ์ ๊ฐ๋ฅ
- ์ฌ๋ฌ ๊ณณ์์ ๋์ผํ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ฉด ์๋์น ์์ ๋ถ์์ฉ ๋ฐ์ ๊ฐ๋ฅ
05. ์ค์ ์์ ์ฝ๋๋ก ๋ฐฐ์ฐ๋ Immutable Object๐ป
Extensible ์์ฑ
๊ฐ์ฒด์ ํ์ฅ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ๊ฐ์ฒด๋ ํ์ฅ ๊ฐ๋ฅํฉ๋๋ค. ํ์ฅ ๊ฐ๋ฅํ ๊ฐ์ฒด๋ ์๋ก์ด ์์ฑ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- Object.isExtensible(obj): ๊ฐ์ฒด๊ฐ ํ์ฅ ๊ฐ๋ฅํ์ง ์ฌ๋ถ๋ฅผ ๋ฐํํฉ๋๋ค.
- Object.preventExtensions(obj): ๊ฐ์ฒด๋ฅผ ํ์ฅ ๋ถ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค. ์๋ก์ด ์์ฑ์ ์ถ๊ฐํ ์ ์์ง๋ง ๊ธฐ์กด ์์ฑ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
let obj = { a: 1 };
console.log(Object.isExtensible(obj)); // true
Object.preventExtensions(obj);
console.log(Object.isExtensible(obj)); // false
obj.b = 2; // ์ถ๊ฐ ๋ถ๊ฐ๋ฅ
console.log(obj.b); // undefined
Seal ์์ฑ
๊ฐ์ฒด๋ฅผ ๋ฐ๋ดํ๋ฉด ์๋ก์ด ์์ฑ์ ์ถ๊ฐํ๊ฑฐ๋ ๊ธฐ์กด ์์ฑ์ ์ญ์ ํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ธฐ์กด ์์ฑ์ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
- Object.isSealed(obj): ๊ฐ์ฒด๊ฐ ๋ฐ๋ด๋์๋์ง ์ฌ๋ถ๋ฅผ ๋ฐํํฉ๋๋ค.
- Object.seal(obj): ๊ฐ์ฒด๋ฅผ ๋ฐ๋ดํฉ๋๋ค. ๊ฐ์ฒด์ ์์ฑ์ ์ถ๊ฐํ๊ฑฐ๋ ์ญ์ ํ ์ ์๊ฒ ๋๋ฉฐ, ๊ฐ์ฒด๋ ์๋์ผ๋ก ํ์ฅ ๋ถ๊ฐ๋ฅ ์ํ๊ฐ ๋ฉ๋๋ค.
let obj = { a: 1 };
console.log(Object.isSealed(obj)); // false
Object.seal(obj);
console.log(Object.isSealed(obj)); // true
obj.b = 2; // ์ถ๊ฐ ๋ถ๊ฐ๋ฅ
delete obj.a; // ์ญ์ ๋ถ๊ฐ๋ฅ
console.log(obj); // { a: 1 }
obj.a = 3; // ๋ณ๊ฒฝ ๊ฐ๋ฅ
console.log(obj); // { a: 3 }
Freeze ์์ฑ
๊ฐ์ฒด๋ฅผ ๋๊ฒฐํ๋ฉด ์๋ก์ด ์์ฑ์ ์ถ๊ฐํ๊ฑฐ๋ ๊ธฐ์กด ์์ฑ์ ์ญ์ ํ ์ ์๊ณ , ์์ฑ์ ๊ฐ๋ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
- Object.isFrozen(obj): ๊ฐ์ฒด๊ฐ ๋๊ฒฐ๋์๋์ง ์ฌ๋ถ๋ฅผ ๋ฐํํฉ๋๋ค.
- Object.freeze(obj): ๊ฐ์ฒด๋ฅผ ๋๊ฒฐํฉ๋๋ค. ๊ฐ์ฒด๋ ์๋์ผ๋ก ๋ฐ๋ด ์ํ๊ฐ ๋๋ฉฐ, ์์ฑ ๊ฐ๋ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
let obj = { a: 1 };
console.log(Object.isFrozen(obj)); // false
Object.freeze(obj);
console.log(Object.isFrozen(obj)); // true
obj.b = 2; // ์ถ๊ฐ ๋ถ๊ฐ๋ฅ
delete obj.a; // ์ญ์ ๋ถ๊ฐ๋ฅ
obj.a = 3; // ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅ
console.log(obj); // { a: 1 }
ํ์ ๊ฐ์ฒด ์ฒ๋ฆฌ
๊ฐ์ฒด์ ํ์ ๊ฐ์ฒด์ ๋ํด์๋ seal์ด๋ freeze ๋ฉ์๋๋ฅผ ํธ์ถํด๋ ์๋์ผ๋ก ์ํฅ์ ๋ฐ์ง ์์ต๋๋ค. ํ์ ๊ฐ์ฒด์ ๋ํด์๋ ๋์ผํ ๋ฉ์๋๋ฅผ ํธ์ถํด์ผ ํฉ๋๋ค.
let obj = {
a: 1,
b: {
c: 2
}
};
Object.freeze(obj);
console.log(Object.isFrozen(obj)); // true
console.log(Object.isFrozen(obj.b)); // false
Object.freeze(obj.b);
console.log(Object.isFrozen(obj.b)); // true
์ด์ ๊ฐ์ด, ๊ฐ์ฒด์ ํ์ฅ ๊ฐ๋ฅ์ฑ, ๋ฐ๋ด ๋ฐ ๋๊ฒฐ ์ํ๋ ํด๋น ๊ฐ์ฒด์ ์ง์ ์ ์ธ ์์ฑ์๋ง ์ํฅ์ ๋ฏธ์น๋ฉฐ, ํ์ ๊ฐ์ฒด์ ๋ํด์๋ ๋ณ๋๋ก ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
06. ์ฑ๋ฅ ํ ์คํธ: ๋ถ๋ณ ๊ฐ์ฒด vs ๊ฐ๋ณ ๊ฐ์ฒดโ๏ธ
์ฑ๋ฅ ๋น๊ต
๋ถ๋ณ ๊ฐ์ฒด๋ ์ํ๋ฅผ ๋ณต์ฌํ์ฌ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ฏ๋ก, ๋์ฉ๋ ๋ฐ์ดํฐ์์๋ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ํ์ง๋ง, ์ด๋ฌํ ์ฑ๋ฅ ์ ํ๋ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ๋น๋๊ฐ ๋ฎ์ ๊ฒฝ์ฐ์๋ ๋ฌด์ํ ์ ์๋ ์์ค์
๋๋ค.
๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ๋น๊ต
๊ฐ๋ณ ๊ฐ์ฒด๋ ์ฐธ์กฐ๋ฅผ ๊ณต์ ํ๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ ์ต๋๋ค. ๋ฐ๋ฉด, ๋ถ๋ณ ๊ฐ์ฒด๋ ๋ณ๊ฒฝ ์๋ง๋ค ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ฆ๊ฐํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ต์ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ์ด๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ค์ํ ์ต์ ํ ๊ธฐ๋ฒ์ ์ฌ์ฉํฉ๋๋ค.