๊ฐ์ฒด๋ฅผ ๋ค๋ฃจ๋ฉด์ ํ๋กํผํฐ(Property)์ ๋ํด ์ด๋์ ๋ ์๊ณ ์์์ฃ ? ์ด์ ๊ทธ ํ๋กํผํฐ๋ฅผ ๋ฏ์ด๋ด ๋๋ค! ํ์ง๋ง ๋ฐ๋์ ์์์ผ ํ๋ ๋ด์ฉ์ ๋ดํฌํ์ง ์์ผ๋ฏ๋ก, ํ์์ ์ํ ์ฐธ์กฐ๋ก ์ ๊ทผํด์ฃผ์ธ์.
์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ํ๋กํผํฐ๋ฅผ ์์ฑํ ๋ ํ๋กํผํฐ์ ์ํ๋ฅผ ๋ํ๋ด๋ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ(Property Attribute)๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์๋ ์ ์ํฉ๋๋ค.
๊ทธ ์ ์, ๋ด๋ถ ์ฌ๋กฏ(Internal Slot)๊ณผ ๋ด๋ถ ๋ฉ์๋(Internal Method)์ ๋ํด ์ง๊ณ ๋์ด๊ฐ์ฃ . ๋ด๋ถ ์ฌ๋กฏ๊ณผ ๋ด๋ถ ๋ฉ์๋๋ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ๊ตฌํ ์๊ณ ๋ฆฌ์ฆ์ ์ค๋ช ํ๊ธฐ ์ํด ECMAScript ์ฌ์์์ ์ฌ์ฉํ๋ ์์ฌ ํ๋กํผํฐ(Pseudo Property)์ ์์ฌ ๋ฉ์๋(Pseudo Method)์ ๋๋ค.
์ ๊ทธ๋ฆผ์ฒ๋ผ ์ด์ค ๋๊ดํธ([[]]
)๋ก ๊ฐ์ผ ์ด๋ฆ๋ค์ด ๋ด๋ถ ์ฌ๋กฏ๊ณผ ๋ด๋ถ ๋ฉ์๋์
๋๋ค. ์์น์ ์ผ๋ก ์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ด๋ถ ์ฌ๋กฏ๊ณผ ๋ด๋ถ ๋ฉ์๋์ ์ง์ ์ ์ธ ์ ๊ทผ ๋ฐ ํธ์ถ์ ๊ธ์งํ๊ณ ์์ต๋๋ค. ๋จ ์ผ๋ถ์ ํํด ๊ฐ์ ์ ์ผ๋ก ์ ๊ทผ ๊ฐ๋ฅํ ์๋จ์ ์ ๊ณตํฉ๋๋ค.
์๋ฅผ ๋ค์ด ๋ชจ๋ ๊ฐ์ฒด๋ [[Prototype]]
์ด๋ผ๋ ๋ด๋ถ ์ฌ๋กฏ์ ๊ฐ๊ณ , __proto__
๋ฅผ ํตํด ๊ฐ์ ์ ์ผ๋ก ์ ๊ทผํ ์ ์์ต๋๋ค. ์๋ ์ฒ๋ผ์!
const obj = {};
obj.[[Prototype]]; // SyntaxError: Unexpected token '['
obj.__proto__; // {constructor: ฦ,ย โฆ}
์, ๊ทธ๋ผ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ์ ๋ํด ์์๋ณผ ์ฐจ๋ก์ ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ด ๊ด๋ฆฌํ๋ ๋ด๋ถ ์ํ ๊ฐ(Meta Property)์ธ ๋ด๋ถ ์ฌ๋กฏ์ ๋๋ค.
ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ์ ์ง์ ์ ๊ทผํ ์๋ ์์ต๋๋ค. ์ด์ ๋ ์์ ํ์ฃ ? ๊ทธ๋ฌ๋ Object.getOwnPropertyDescriptor
๋ฉ์๋๋ก ๊ฐ์ ์ ์ธ ํ์ธ์ด ๊ฐ๋ฅํฉ๋๋ค. ์ด ๋ฉ์๋๋ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ ํ๋กํผํฐ ๋์คํฌ๋ฆฝํฐ(Property Descriptor) ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. ๋ง์ฝ ์กด์ฌํ์ง ์๋ ํ๋กํผํฐ์ ๋ํด ๋์คํฌ๋ฆฝํฐ๋ฅผ ์๊ตฌํ๋ฉด undefined
๊ฐ ๋ฐํ๋ฉ๋๋ค.
const person = {
name : 'amy'
};
person.age = 16;
console.log(Object.getOwnPropertyDescriptors(person));
/*
{
name: { value: 'amy', writable: true, enumerable: true, configurable: true },
age: { value: 16, writable: true, enumerable: true, configurable: true }
}
*/
ES8์๋ ๋ณต์์ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ getOwnPropertyDescriptors
ํจ์๋ ์ถ๊ฐ๋์์ง๋ง... ์์๋ง ๋์ธ์!
ํ๋กํผํฐ๋ ๋ฐ์ดํฐ ํ๋กํผํฐ(Data Property)์ ์ ๊ทผ์ ํ๋กํผํฐ(Accessor Property)๋ก ๊ตฌ๋ถํฉ๋๋ค.
-
๋ฐ์ดํฐ ํ๋กํผํฐ๋ ํค์ ๊ฐ์ผ๋ก ๊ตฌ์ฑ๋๊ณ ์ง๊ธ๊ป ์ดํด๋ณธ ๋ชจ๋ ํ๋กํผํฐ๊ฐ ์ฌ๊ธฐ์ ํด๋นํ๋ฉฐ, ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ด ํ๋กํผํฐ๋ฅผ ์์ฑํ ๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์๋ ์ ์ํฉ๋๋ค.
ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ ์ค๋ช [[Value]]
โ ํ๋กํผํฐ ํค๋ฅผ ํตํด ํ๋กํผํฐ ๊ฐ์ ์ ๊ทผํ๋ฉด ๋ฐํ๋๋ ๊ฐ์ ๋๋ค.
โ ํ๋กํผํฐ ํค๋ฅผ ํตํด ํ๋กํผํฐ ๊ฐ์ ๋ณ๊ฒฝํ๋ฉด[[Value]]
์ ๊ฐ์ ์ฌํ ๋นํฉ๋๋ค. ์ด ๋ ํ๋กํผํฐ๊ฐ ์์ผ๋ฉด ํ๋กํผํฐ๋ฅผ ๋์ ์์ฑํ๊ณ ์์ฑ๋ ํ๋กํผํฐ[[Value]]
์ ๊ฐ์ ์ ์ฅํฉ๋๋ค.[[Writable]]
โ ํ๋กํผํฐ ๊ฐ์ ๋ณ๊ฒฝ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ฉฐ boolean ๊ฐ์ ๊ฐ์ต๋๋ค.
โ[[Writable]]
์ด false์ธ ๊ฒฝ์ฐ ํด๋น ํ๋กํผํฐ์[[Value]]
๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ์ฝ๊ธฐ ์ ์ฉ ํ๋กํผํฐ๊ฐ ๋ฉ๋๋ค.[[Enumerable]]
โ ํ๋กํผํฐ์ ์ด๊ฑฐ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ฉฐ boolean ๊ฐ์ ๊ฐ์ต๋๋ค.
โ[[Enumerable]]
์ ๊ฐ์ด false์ธ ๊ฒฝ์ฐ ํด๋น ํ๋กํผํฐ๋ for ... in ์ด๋ Object.keys ๋ฉ์๋ ๋ฑ์ผ๋ก ์ด๊ฑฐํ ์ ์์ต๋๋ค.[[Configurable]]
โ ํ๋กํผํฐ์ ์ฌ์ ์ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ฉฐ boolean๊ฐ์ ๊ฐ์ต๋๋ค.
โ[[Configurable]]
์ ๊ฐ์ด false์ธ ๊ฒฝ์ฐ ์ญ์ ๋ ๋ณ๊ฒฝ์ด ๊ธ์ง๋ฉ๋๋ค. ๋จ,[[Writable]]
์ด true์ธ ๊ฒฝ์ฐ๋[[Value]]
์ ๋ณ๊ฒฝ๊ณผ[[Writable]]
์ false๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ด ํ์ฉ๋ฉ๋๋ค. -
์ ๊ทผ์ ํ๋กํผํฐ๋ ์์ฒด์ ์ผ๋ก ๊ฐ์ ๊ฐ์ง ์์ผ๋ ๋ฐ์ดํฐ ํ๋กํผํฐ์ ๊ฐ์ ์ฝ๊ฑฐ๋ ์์ ํ ๋ ํธ์ถ๋๋ ์ ๊ทผ์ ํจ์(Accessor Function)๋ก ๊ตฌ์ฑ๋ ํ๋กํผํฐ์ ๋๋ค. ์ ๊ทผ์ ํจ์๋
getter/setter
ํจ์๋ผ๊ณ ๋ ๋ถ๋ฆ ๋๋ค.ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ ์ค๋ช [[Get]]
โ ์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ํตํด ๋ฐ์ดํฐ ํ๋กํผํฐ ๊ฐ์ ์ฝ์ ๋ ํธ์ถ๋๋ ์ ๊ทผ์ ํจ์์ ๋๋ค.
โ ์ ๊ทผ์ ํ๋กํผํฐ ํค๋ก ํ๋กํผํฐ ๊ฐ์ ์ ๊ทผํ๋ฉด ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ[[Get]]
์ ๊ฐ, getter ํจ์๊ฐ ํธ์ถ๋๊ณ ๊ทธ ๊ฒฐ๊ณผ๊ฐ ํ๋กํผํฐ ๊ฐ์ผ๋ก ๋ฐํ๋ฉ๋๋ค.[[Set]]
โ ์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ํตํด ๋ฐ์ดํฐ ํ๋กํผํฐ์ ๊ฐ์ ์ ์ฅํ ๋ ํธ์ถ๋๋ ์ ๊ทผ์ ํจ์์ ๋๋ค.
โ ์ ๊ทผ์ ํ๋กํผํฐ ํค๋ก ํ๋กํผํฐ ๊ฐ์ ์ ์ฅํ๋ฉด ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ[[Set]]
๊ฐ, ์ฆ setter ํจ์๊ฐ ํธ์ถ๋๊ณ ๊ทธ ๊ฒฐ๊ณผ๊ฐ ํ๋กํผํฐ ๊ฐ์ผ๋ก ์ ์ฅ๋ฉ๋๋ค.[[Enumerable]]
โ ๋ฐ์ดํฐ ํ๋กํผํฐ์ enumerable๊ณผ ๊ฐ์ต๋๋ค. [[Configurable]]
โ ๋ฐ์ดํฐ ํ๋กํผํฐ์ configurable๊ณผ ๊ฐ์ต๋๋ค. - ์ ๊ทผ์ ํ๋กํผํฐ๋ก ํ๋กํผํฐ ๊ฐ์ ์ ๊ทผํ๋ฉด ์ด๋ป๊ฒ ๋์ํ ๊น์?
- 1๏ธโฃ ํ๋กํผํฐ ํค๊ฐ ์ ํจํ์ง ํ์ธํฉ๋๋ค. ํ๋กํผํฐ ํค๋ ๋ฌธ์์ด์ด๊ฑฐ๋ ์ฌ๋ณผ์ด์ด์ผ ํฉ๋๋ค.
- 2๏ธโฃ ํ๋กํ ํ์ ์ฒด์ธ์์ ํ๋กํผํฐ๋ฅผ ๊ฒ์ํฉ๋๋ค.
- 3๏ธโฃ ๊ฒ์๋ ํ๋กํผํฐ๊ฐ ๋ฐ์ดํฐ ํ๋กํผํฐ์ธ์ง ์ ๊ทผ์ ํ๋กํผํฐ์ธ์ง ํ์ธํฉ๋๋ค.
- 4๏ธโฃ ์ ๊ทผ์ ํ๋กํผํฐ์ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ
[[Get]]
์ ๊ฐ์ธ getter๋ฅผ ํธ์ถํ์ฌ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค.
- ์ ๊ทผ์ ํ๋กํผํฐ๋ก ํ๋กํผํฐ ๊ฐ์ ์ ๊ทผํ๋ฉด ์ด๋ป๊ฒ ๋์ํ ๊น์?
์ ๊น, ํ๋กํ ํ์ ์ฒด์ธ?
- ์ด๋ ค์ด ๋จ์ด๊ฐ ๋์๋ค์? ํ๋กํ ํ์
์ฒด์ธ์ด๋ผ๋. ํ๋กํ ํ์
(Prototype)์ ์ด๋ค ๊ฐ์ฒด์ ์์(๋ถ๋ชจ) ๊ฐ์ฒด ์ญํ ์ ํ๋
๊ฐ์ฒด
์ ๋๋ค. ์ด ํ๋กํ ํ์ ์ ํตํด ์ฐ๋ฆฌ๋ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋จ์ฒ๋ผ ์์๊ณผ ํ์ฅ์ ํ ์ ์์ฃ . ํ๋กํ ํ์ ์ฒด์ธ(Prototype Chain)์ ํ๋กํ ํ์ ์ด ๋จ๋ฐฉํฅ ๋งํฌ๋ ๋ฆฌ์คํธ(Linked List)๋ก ์ฐ๊ฒฐ๋ ์์ ๊ตฌ์กฐ๋ฅผ ๋ปํฉ๋๋ค.
์๋ก์ด ํ๋กํผํฐ๋ฅผ ์ถ๊ฐํ๋ฉด์ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ๋ฅผ ๋ช ์์ ์ผ๋ก ์ ์ํ๊ฑฐ๋, ๊ธฐ์กด ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ๋ฅผ ์ฌ์ ์ํ๋ ๊ฒ์ ๋๋ค.
Object.defineProperty ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ๋ฅผ ์ ์ํ ์ ์์ต๋๋ค.
const person = {};
Object.defineProperty(person, 'firstName', {
value : 'Chil',
writable : true,
enumerable : true,
configurable : true
})
Object.defineProperty(person, 'lastName', {
value : 'Amy',
})
let descriptor = Object.getOwnPropertyDescriptor(person, 'firstName');
console.log('firstName', descriptor);
// firstName {
// value: 'Chil',
// writable: true,
// enumerable: true,
// configurable: true
// }
descriptor = Object.getOwnPropertyDescriptor(person, 'lastName');
console.log('lastName', descriptor);
// lastName {
// value: 'Amy',
// writable: false,
// enumerable: false,
// configurable: false
// }
console.log(Object.keys(person));
//[ 'firstName' ]
person.lastName = "J";
delete person.lastName;
descriptor = Object.getOwnPropertyDescriptor(person, 'lastName');
console.log('lastName', descriptor);
// lastName {
// value: 'Amy',
// writable: false,
// enumerable: false,
// configurable: false
// }
Object.defineProperty(person, 'fullName', {
get() {
return `${this.firstName} ${this.lastName}`
}
set(name){
[this.firstName, this.lastName] = name.split(' ');
}
enumberable : true,
configurable : true
});
descriptor = Object.getOwnPropertyDescriptor(person, 'fullName');
console.log(descriptor);
// {
// get: [Function: get],
// set: [Function: set],
// enumerable: false,
// configurable: true
// }
person.fullName = "thin Amy";
console.log(person);
// { firstName: 'thin' }
ํ๋กํผํฐ ๋์คํฌ๋ฆฝํฐ ๊ฐ์ฒด์์ ์๋ต๋ ์ดํธ๋ฆฌ๋ทฐํธ๋ ๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ณธ๊ฐ์ด ์ ์ฉ๋ฉ๋๋ค.
ํ๋กํผํฐ ๋์คํฌ๋ฆฝํฐ ๊ฐ์ฒด์ ํ๋กํผํฐ | ๋์ํ๋ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ | ์๋ตํ์ ๋์ ๊ธฐ๋ณธ๊ฐ |
---|---|---|
value | [[Value]] |
undefined |
get | [[Get]] |
undefined[ |
set | [[Set]] |
undefined |
writable | [[Writable]] |
false |
enumerable | [[Enumerable]] |
false |
configurable | [[Configurable]] |
false |
๋ณต์์ ํ๋กํผํฐ๋ฅผ ์ ์ํ๋ defineProperties
ํจ์๋ ์กด์ฌํ์ง๋ง... ์์๋ง ๋์ธ์!
๊ฐ์ฒด๋ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ด๋ฏ๋ก ์ฌํ ๋น ์์ด ์ง์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๋ ค๋ฉด ์ด๋ป๊ฒ ํ ๊น์?
์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ฐ์ฒด ๋ณ๊ฒฝ ๋ฐฉ์ง๋ฅผ ์ํด ์๋์ ๊ฐ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
๊ตฌ๋ถ | ๋ฉ์๋ | ํ๋กํผํฐ ์ถ๊ฐ | ํ๋กํผํฐ ์ญ์ | ํ๋กํผํฐ ๊ฐ ์ฝ๊ธฐ | ํ๋กํผํฐ ๊ฐ ์ฐ๊ธฐ | ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ ์ฌ์ ์ |
---|---|---|---|---|---|---|
๊ฐ์ฒด ํ์ฅ ๊ธ์ง | Object.preventExtensions | X | O | O | O | O |
๊ฐ์ฒด ๋ฐ๋ด | Object.seal | X | X | O | O | X |
๊ฐ์ฒด ๋๊ฒฐ | Object.freeze | X | X | O | X | X |
์ถ๊ฐ์ ์ผ๋ก ๊ฐ์ฒด๋ฅผ ๋ถ๋ณ ๊ฐ์ฒด๋ก ๋ง๋ค๊ธฐ ์ํด์๋ Object.freeze ๋ฉ์๋๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํด์ผ ํฉ๋๋ค.
function deepFreeze(target){
if(target && typeof target === 'object' && !Object.isFrozen(target)){
Object.freeze(target);
Object.keys(target).forEach(key => deepFreeze(target[key]));
}
}
const person = {
name : 'Amy',
address: {city : 'LA'}
};
deepFreeze(person)
console.log(Object.isFrozen(person)); // true
console.log(Object.isFrozen(person.address)); // true
person.address.city = 'Seoul';
console.log(person); // {name: 'Amy', address: {city: 'Seoul'}}