16์ฅ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ
๋ด๋ถ ์ฌ๋กฏ๊ณผ ๋ด๋ถ ๋ฉ์๋
์ด์ค ๋๊ดํธ([[...]])๋ก ๊ฐ์ผ ์ด๋ฆ๋ค์ด ๋ด๋ถ ์ฌ๋กฏ๊ณผ ๋ด๋ถ ๋ฉ์๋๋ค.
๋ด๋ถ ์ฌ๋กฏ๊ณผ ๋ด๋ถ ๋ฉ์๋๋ ECMAScript ์ฌ์์ ์ ์๋ ๋๋ก ๊ตฌํ๋์ด ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์์ ์ค์ ๋ก ๋์ํ์ง๋ง ๊ฐ๋ฐ์๊ฐ ์ง์ ์ ๊ทผํ ์ ์๋๋ก ์ธ๋ถ๋ก ๊ณต๊ฐ๋ ๊ฐ์ฒด์ ํ๋กํผํฐ๋ ์๋๋ค.
const o = {};
// ๋ด๋ถ ์ฌ๋กฏ์ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ๋ด๋ถ ๋ก์ง์ด๋ฏ๋ก ์ง์ ์ ๊ทผํ ์ ์๋ค.
o.[[Prototype]] // Uncaught StyntaxError: Unexpected token '['
// ์ผ๋ถ ๋ด๋ถ ์ฌ๋กฏ๊ณผ ๋ด๋ถ ๋ฉ์๋์ ํํ์ฌ ๊ฐ์ ์ ์ผ๋ก ์ ๊ทผํ ์ ์๋ ์๋จ์ ์ ๊ณตํ๊ธฐ๋ ํ๋ค.
o.__proto__ // Object.prototype
์์ฑ์ผ ๊ธฐ์ค Object.prototype.__proto__ ๋ Deprecated ๋์๋ค.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ์ ํ๋กํผํฐ ๋์คํฌ๋ฆฝํฐ ๊ฐ์ฒด
์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ํ๋กํผํฐ๋ฅผ ์์ฑํ ๋ ํ๋กํผํฐ์ ์ํ๋ฅผ ๋ํ๋ด๋ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์๋ ์ ์ํ๋ค.
ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ด ๊ด๋ฆฌํ๋ ๋ด๋ถ ์ํ ๊ฐ์ธ ๋ด๋ถ ์ฌ๋กฏ [[Value]], [[Writable]], [[Enumerable]], [[Configurable]]์ด๋ค. ๋ฐ๋ผ์ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ์ ์ง์ ์ ๊ทผํ ์ ์์ง๋ง [ic]Object.getOwnPropertyDescriptor[/ic], [ic]Object.getOwnPropertyDescriptors[/ic] ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ ์ ์ผ๋ก ํ์ธํ ์๋ ์๋ค.
const person = {
name: 'Lee',
};
// ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ ํ๋กํผํฐ ๋์คํฌ๋ฆฝํฐ ๊ฐ์ฒด๋ฅผ ๋ฐํ
console.log(Object.getOwnPropertyDescriptor(person, 'name'));
// {value: 'Lee', writable: true, enumerable: true, configurable: true}
person.age = 10;
console.log(Object.getOwnPropertyDescriptors(person));
// {
// name: {value: 'Lee', writable: true, enumerable: true, configurable: true},
// age: {value: 10, writable: true, enumerable: true, configurable: true},
// }
๋ฐ์ดํฐ ํ๋กํผํฐ์ ์ ๊ทผ์ ํ๋กํผํฐ
๋ฐ์ดํฐ ํ๋กํผํฐ
ํค์ ๊ฐ์ผ๋ก ๊ตฌ์ฑ๋ ์ผ๋ฐ์ ์ธ ํ๋กํผ๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ด ํ๋กํผํฐ๋ฅผ ์์ฑํ ๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์๋ ์ ์๋๋ค.
ํ๋กํผํฐ๊ฐ ์์ฑ ๋ ๋ [[Value]] ์ ๊ฐ์ ํ๋กํผํฐ ๊ฐ์ผ๋ก ์ด๊ธฐํ๋๋ฉฐ [[Writable]], [[Enumerable]], [[Configurable]] ์ ๊ฐ์ true๋ก ์ด๊ธฐํ๋๋ค.
ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ | ํ๋กํผํฐ ๋์คํฌ๋ฆฝํฐ ๊ฐ์ฒด์ ํ๋กํผํฐ | ์ค๋ช |
[[Value]] | value | - ํ๋กํผํฐ ํค๋ฅผ ํตํด ํ๋กํผํฐ ๊ฐ์ ์ ๊ทผํ๋ฉด ๋ฐํ๋๋ ๊ฐ - ํ๋กํผํฐ ํค๋ฅผ ํตํด ํ๋กํผํฐ ๊ฐ์ ๋ณ๊ฒฝํ๋ฉด [[Value]] ์ ๊ฐ์ ์ฌํ ๋น - ํ๋กํผํฐ๊ฐ ์์ผ๋ฉด ํ๋กํผํฐ๋ฅผ ๋์ ์์ฑํ๊ณ ์์ฑํ ํ๋กํผํฐ์ [[Value]]์ ๊ฐ์ ์ ์ฅ |
[[Writable]] | writable | - ํ๋กํผํฐ ๊ฐ์ ๋ณ๊ฒฝ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ฉฐ ๋ถ๋ฆฌ์ธ ๊ฐ์ ๊ฐ์ - ๊ฐ์ด false์ธ ๊ฒฝ์ฐ [[Value]] ์ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ์ฝ๊ธฐ ์ ์ฉ ํ๋กํผํฐ๊ฐ ๋จ |
[[Enumerable]] | enumerable | - ํ๋กํผํฐ์ ์ด๊ฑฐ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ฉฐ ๋ถ๋ฆฌ์ธ ๊ฐ์ ๊ฐ์ - ๊ฐ์ด false์ธ ๊ฒฝ์ฐ for...in ๋ฌธ์ด๋ Object.keys ๋ฉ์๋ ๋ฑ์ผ๋ก ์ด๊ฑฐํ ์ ์์ |
[[Configurable]] | configurable | - ํ๋กํผํฐ์ ์ฌ์ ์ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ฉฐ ๋ถ๋ฆฌ์ธ ๊ฐ์ ๊ฐ์ - ๊ฐ์ด false ์ธ ๊ฒฝ์ฐ ํ๋กํผํฐ์ ์ญ์ , ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ ๊ฐ์ ๋ณ๊ฒฝ์ด ๊ธ์ง ๋จ - [[Writable]] ๊ฐ true์ธ ๊ฒฝ์ฐ [[Value]], [[Writable]] ์ ๋ณ๊ฒฝ์ ํ์ฉ ๋จ |
์ ๊ทผ์ ํ๋กํผํฐ
์์ฒด์ ์ผ๋ก๋ ๊ฐ์ ๊ฐ์ง ์์ผ๋ฉฐ ๋ค๋ฅธ ๋ฐ์ดํฐ ํ๋กํผํฐ ๊ฐ์ ์ฝ๊ฑฐ๋ ์ง์ ํ ๋ ํธ์ถ๋๋ ์ ๊ทผ์ ํจ์๋ก ๊ตฌ์ฑ๋ ํ๋กํผํฐ๋ค.
ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ | ํ๋กํผํฐ ๋์คํฌ๋ฆฝํฐ ๊ฐ์ฒด์ ํ๋กํผํฐ | ์ค๋ช |
[[Get]] | get | - ์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ํตํด ๋ฐ์ดํฐ ํ๋กํผํฐ์ ๊ฐ์ ์ฝ์ ๋ ํธ์ถ๋๋ ์ ๊ทผ์ ํจ์ - ์ ๊ทผ์ ํ๋กํผํฐ ํค๋ก ํ๋กํผํฐ ๊ฐ์ ์ ๊ทผํ๋ฉด ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ [[Get]]์ ๊ฐ์ธ getter ํจ์๊ฐ ํธ์ถ๋๊ณ ๊ทธ ๊ฒฐ๊ณผ๊ฐ ํ๋กํผํฐ ๊ฐ์ผ๋ก ๋ฐํ |
[[Set]] | set | - ์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ํตํด ๋ฐ์ดํฐ ํ๋กํผํฐ์ ๊ฐ์ ์ ์ฅํ ๋ ํธ์ถ๋๋ ์ ๊ทผ์ ํจ์ - ์ ๊ทผ์ ํ๋กํผํฐ ํค๋ก ํ๋กํผํฐ ๊ฐ์ ์ ์ฅํ๋ฉด ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ [[Set]]์ ๊ฐ์ธ setter ํจ์๊ฐ ํธ์ถ๋๊ณ ๊ทธ ๊ฒฐ๊ณผ๊ฐ ํ๋กํผํฐ ๊ฐ์ผ๋ก ์ ์ฅ |
[[Enumerable]] | enumerable | ๋ฐ์ดํฐ ํ๋กํผํฐ์ [[Enumerable]]๊ณผ ๊ฐ์ |
[[Configurable]] | configurable | ๋ฐ์ดํฐ ํ๋กํผํฐ์ [[Configurable]]๊ณผ ๊ฐ์ |
const person = {
// ๋ฐ์ดํฐ ํ๋กํผํฐ
firstName: 'Rose',
lastName: 'Park',
// getter ํจ์
get fullName() {
return `${this.firstName} ${this.lastName}`;
},
// setter ํจ์
set fullName(name) {
[this.firstName, this.lastName] = name.split(' ');
},
};
// ๋ฐ์ดํฐ ํ๋กํผํฐ๋ฅผ ํตํ ํ๋กํผํฐ ๊ฐ์ ์ฐธ์กฐ
console.log(person.firstName);
// Rose
// ์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ํตํ ํ๋กํผํฐ ๊ฐ์ ์ฐธ์กฐ
console.log(person.fullName);
// Rose Park
// ์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ํตํ ํ๋กํผํฐ ๊ฐ์ ์ ์ฅ
person.fullName = 'Jennie Kim';
console.log(person);
// {firstName: 'Kim', lastName: 'Jennie', fullName: [Getter/Setter]}
// firstName์ ๋ฐ์ดํฐ ํ๋กํผํฐ
console.log(Object.getOwnPropertyDescriptor(person, 'firstName'));
// {value: 'rose', writable: true, enumerable: true, configurable: true}
// firstName์ ์ ๊ทผ์ ํ๋กํผํฐ
console.log(Object.getOwnPropertyDescriptor(person, 'fullName'));
// {get: f, set: f, enumerable: true, configurable: true};
ํ๋กํผํฐ ์ ์
ํ๋กํผํฐ ์ ์๋ ์๋ก์ด ํ๋กํผํฐ๋ฅผ ์ถ๊ฐํ๋ฉด์ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ๋ฅผ ๋ช ์์ ์ผ๋ก ์ ์ํ๊ฑฐ๋, ๊ธฐ์กด ํ๋กํผํฐ์ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ๋ฅผ ์ฌ์ ์ํ๋ ๊ฒ์ ๋งํ๋ค.
const person1 = {};
// ๋ฐ์ดํฐ ํ๋กํผํฐ ์ ์
Object.defineProperty(person1, 'firstName', {
value: 'Rose',
writable: true,
enumerable: true,
configurable: true,
});
// ๋์คํฌ๋ฆฝํฐ ๊ฐ์ฒด์ ํ๋กํผํฐ๋ฅผ ๋๋ฝ์ํค๋ฉด undefined, false ๊ฐ ๊ธฐ๋ณธ๊ฐ
console.log(Object.getOwnPropertyDescriptor(person1, 'firstName'));
// {value: 'Rose', writable: true, enumerable: true, configurable: true};
// ์ ๊ทผ์ ํ๋กํผํฐ ์ ์
Object.defineProperty(person1, 'changeName', {
get() {
return `${this.firstName}`;
},
set(name) {
// [[Writable]]์ ๊ฐ์ด true ์ด๋ฏ๋ก [[Value]]์ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์์
this.firstName = name;
},
enumerable: true,
configurable: true,
});
person1.changeName = 'Jennie';
console.log(person1);
// {firstName: 'Jennie', changeName: [Getter/Setter]}
const person2 = {};
// Object.defineProperties ๋ฉ์๋๋ ์ฌ๋ฌ ๊ฐ์ ํ๋กํผํฐ๋ฅผ ํ ๋ฒ์ ์ ์ ๊ฐ๋ฅ
Object.defineProperties(person2, {
firstName: {
value: 'Jennie',
writable: true,
enumerable: true,
configurable: true,
},
lastName: {
value: 'Lee',
writable: true,
enumerable: true,
configurable: true,
},
fullName: {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(name) {
[this.firstName, this.lastName] = name.split(' ');
},
enumerable: true,
configurable: true,
},
});
person2.fullName = 'La lisa';
console.log(person2);
// {firstName: 'La', lastName: 'lisa', fullName: [Getter/Setter]}
๊ฐ์ฒด ๋ณ๊ฒฝ ๋ฐฉ์ง
๊ฐน์ฒด๋ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ด๋ฏ๋ก ์ฌํ ๋น ์์ด ์ง์ ๋ณ๊ฒฝํ ์ ์๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ฐ์ฒด์ ๋ณ๊ฒฝ์ ๋ฐฉ์งํ๋ ๋ค์ํ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค.
๊ฐ์ฒด ํ์ฅ ๊ธ์ง
[ic]Object.preventExtensions[/ic] ๋ฉ์๋๋ ๊ฐ์ฒด์ ํ์ฅ์ ๊ธ์งํ๋ค. ํ์ฅ์ด ๊ธ์ง๋ ๊ฐ์ฒด๋ ํ๋กํผํฐ ์ถ๊ฐ๊ฐ ๊ธ์ง๋๋ค.
ํ์ฅ์ด ๊ฐ๋ฅํ ๊ฐ์ฒด์ธ์ง ์ฌ๋ถ๋ [ic]Object.isExtensible[/ic] ๋ฉ์๋๋ก ํ์ธ ํ ์ ์๋ค.
๊ฐ์ฒด ๋ฐ๋ด
[ic]Object.seal[/ic] ๋ฉ์๋๋ ๊ฐ์ฒด๋ฅผ ๋ฐ๋ดํ๋ค. ๋ฐ๋ด๋ ๊ฐ์ฒด๋ ์ฝ๊ธฐ์ ์ฐ๊ธฐ(๊ฐฑ์ )๋ง ๊ฐ๋ฅํ๋ค.
๋ฐ๋ด๋ ๊ฐ์ฒด์ธ์ง ์ฌ๋ถ๋ [ic]Object.isSealed[/ic] ๋ฉ์๋๋ก ํ์ธ ํ ์ ์๋ค.
๊ฐ์ฒด ๋๊ฒฐ
[ic]Object.freeze[/ic] ๋ฉ์๋๋ ๊ฐ์ฒด๋ฅผ ๋๊ฒฐํ๋ค. ๋๊ฒฐ๋ ๊ฐ์ฒด๋ ์ฝ๊ธฐ๋ง ๊ฐ๋ฅํ๋ค.
๋๊ฒฐ๋ ๊ฐ์ฒด์ธ์ง ์ฌ๋ถ๋ [ic]Object.isFrozen[/ic] ๋ฉ์๋๋ก ํ์ธ ํ ์ ์๋ค.
๋ถ๋ณ ๊ฐ์ฒด
๊ฐ์ฒด์ ์ค์ฒฉ ๊ฐ์ฒด๊น์ง ๋๊ฒฐํ์ฌ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํ ์ฝ๊ธฐ ์ ์ฉ์ ๋ถ๋ณ ๊ฐ์ฒด๋ฅผ ๊ตฌํํ๋ ค๋ฉด ๊ฐ์ฒด๋ฅผ ๊ฐ์ผ๋ก ๊ฐ๋ ๋ชจ๋ ํ๋กํผํฐ์ ๋ํด ์ฌ๊ท์ ์ผ๋ก [ic]Object.freeze[/ic] ๋ฉ์๋๋ฅผ ํธ์ถํด์ผ ํ๋ค.
function deepFreeze(target) {
if (target && typeof target === 'object' && !Object.isFrozen(target)) {
Object.freeze(target);
Object.keys(target).forEach(key => deepFreeze(target[key]));
}
return target;
}