๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ Deep Dive ๋์์ 19์ฅ์ ์ ๋ฆฌํ์์ต๋๋ค.
๊ฐ์ฒด๋ ๋ฆฌํฐ๋ด ํ๊ธฐ๋ฒ ๋๋ ์์ฑ์ ํจ์์ ์ํด ์์ฑ๋๋ฏ๋ก ๊ฒฐ๊ตญ ๋ชจ๋ ๊ฐ์ฒด๋ ์์ฑ์ ํจ์์ ์ฐ๊ฒฐ๋์ด ์๋ค.
ํ๋กํ ํ์
์ ์์ฑ์ ํจ์๊ฐ ์์ฑ๋๋ ์์ ์ ๋๋ถ์ด ์์ฑ๋๋ค.
countructor
ํจ์ ์ ์๊ฐ ํ๊ฐ๋์ด ํจ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ์์ ์ ํ๋กํ ํ์
๋ ๋๋ถ์ด ์์ฑ๋๋ค.
// 19-20
console.log(Person.prototype); // {contructor:f}
function Person(name){
this.name = name;
}
์์ฑ์ ํจ์๋ก์ ํธ์ถํ ์ ์๋ ํจ์๋ ํ๋กํ ํ์ ์ด ์์ฑ๋์ง ์๋๋ค.
// 19-20
const Person = name => {
this.name = name;
}
console.log(Person.prototype); // undefined
ํจ์ ์ ์ธ๋ฌธ์ ๋ฐํ์ ์ด์ ์ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ์ํด ๋จผ์ ์คํ๋๋ค. ๋ฐ๋ผ์ ํจ์ ์ ์ธ๋ฌธ์ผ๋ก ์ ์๋ ์์ฑ์ ํจ์๋ ์ด๋ค ์ฝ๋๋ณด๋ค ๋จผ์ ํ๊ฐ๋์ด ํจ์ ๊ฐ์ฒด๊ฐ ๋๊ณ ์ด๋ ํ๋กํ ํ์
๋ ๋๋ถ์ด ์์ฑ๋๋ค. ์์ฑ๋ ํ๋กํ ํ์
์ ํ๋กํ ํ์
์ ์ธ์ ๋ Object.prototype
์ด๋ค.
๋นํธ์ธ ์์ฑ์ ํจ์๋ ์ผ๋ฐ ํจ์์ ๋ง์ฐฌ๊ฐ์ง๋ก ์์ฑ์ ํจ์๊ฐ ์์ฑ๋๋ ์์ ์ ํ๋กํ ํ์ ์ด ์์ฑ๋๋ค. ๋ชจ๋ ๋นํธ์ธ ์์ฑ์ ํจ์๋ ์ ์ญ ๊ฐ์ฒด๊ฐ ์์ฑ๋๋ ์์ ์ ์์ฑ๋๋ค.
์ด์ฒ๋ผ ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ธฐ ์ด์ ์ ์์ฑ์ ํจ์์ ํ๋กํ ํ์ ์ ์ด๋ฏธ ๊ฐ์ฒดํ๋์ด ์กด์ฌํ๋ค. ์ดํ ์์ฑ์ ํจ์ ๋๋ ๋ฆฌํฐ๋ด ํ๊ธฐ๋ฒ์ผ๋ก ์์ฑํ๋ฉด ํ๋กํ ํ์ ์ ์์ฑ๋ ๊ฐ์ฒด์ [[Prototype]] ๋ด๋ถ ์ฌ๋กฏ์ ํ ๋น๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ํ๊ฐํ์ฌ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ์ถ์ ์ฐ์ฐ OrdinaryObjectCreate๋ฅผ ํธ์ถํ๋ค. ์ด๋ ์ถ์ ์ฐ์ฐ OrdinaryObjectCreate์ ์ ๋ฌ๋๋ ํ๋กํ ํ์ ์ Object.prototypedlek. ์ฆ, ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ์ํด ์์ฑ๋๋ ๊ฐ์ฒด์ ํ๋กํ ํ์ ์ Object.prototype์ด๋ค.
// 19-24
const obj = { x: 1 };
console.log(obj.constructor === Object); // true
console.log(obj.hasOwnProperty('x'); // true
๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ์ํด ์์ฑ๋ ๊ฐ์ฒด์ ๋์ผํ ๊ตฌ์กฐ๋ฅผ ๊ฐ๋๋ค.
// 19-24
const obj = new Object();
obj.x = 1;
console.log(obj.constructor === Object); // true
console.log(obj.hasOwnProperty('x'); // true
์์ฑ์ ํจ์์ ์ํด ์์ฑ๋๋ ๊ฐ์ฒด์ ํ๋กํ ํ์ ์ ์์ฑ์ ํจ์์ prototype ํ๋กํผํฐ์ ๋ฐ์ธ๋ฉ ๋์ด ์๋ ๊ฐ์ฒด๋ค.
function Person(name){
this.name = name;
}
const me = new Person('Lee');
์ฌ์ฉ์ ์ ์ Person๊ณผ ๋๋ถ์ด ์์ฑ๋ ํ๋กํ ํ์ Person.prototype์ ํ๋กํผํฐ๋ contructor๋ฟ์ด๋ค.
// 19-29
function Person(name){
this.name = name;
}
Person.prototype.sayhello = function () {
console.log(`My name is ${this.name}`);
}
const me = new Person('Lee');
// hasOwnProperty๋ Object.prototype์ ๋ฉ์๋๋ค.
console.log(me.hasOwnProperty('name')); // true
me ๊ฐ์ฒด๋ hasOwnProperty๋ฅผ ํธ์ถํ ์ ์๊ณ ์ด๊ฒ์ me ๊ฐ์ฒด๊ฐ Person.prototype ๋ฟ๋ง ์๋๋ผ Object.prototype๋ ์์๋ฐ์๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
Object.getPrototypeOf(me) === Person.prototype; // => true
Object.getPrototypeOf(Person.prototype) === Object.prototypel // => true
์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ฐ์ฒด์ ํ๋กํผํฐ์ ์ ๊ทผํ๋ ค๊ณ ํ ๋ ํด๋น ๊ฐ์ฒด์ ์ ๊ทผํ๋ ค๋ ํ๋กํผํฐ๊ฐ ์๋ค๋ฉด [[Prototype]] ๋ด๋ถ ์ฌ๋กฏ์ ์ฐธ์กฐ๋ฅผ ๋ฐ๋ผ ์์ ์ ๋ถ๋ชจ ์ญํ ์ ํ๋ ํ๋กํ ํ์ ์ ํ๋กํผํฐ๋ฅผ ์์ฐจ์ ์ผ๋ก ๊ฒ์ํ๋ค. ์ด๋ฅผ ํ๋กํ ํ์ ์ฒด์ธ์ด๋ผ๊ณ ํ๋ค.
ํ๋กํ ํ์ ์ ์ฒด์ธ์ ์ต์์์ ์์นํ๋ ๊ฐ์ฒด๋ ์ธ์ ๋ Object.prototype์ด๋ค. ๋ฐ๋ผ์ ๋ชจ๋ ๊ฐ์ฒด๋ Object.prototype์ ์์๋ฐ๋๋ค. Object.prototyp์ ํ๋กํ ํ์ , ์ฆ [[Prototype]]์ ๋ด๋ถ ์ฌ๋กฏ์ ๊ฐ์ null์ ๋๋ค.
// 19-34
// ์ข
์ ์์๋ ํ๋กํผํฐ๋ฅผ ๊ฒ์ํ ์ ์๋ ๊ฒฝ์ฐ
console.log(me.foo); // undefined
ํ๋กํ ํ์ ํ๋กํผํฐ์ ๊ฐ์ ์ด๋ฆ์ ํ๋กํผํฐ๋ฅผ ์ธ์คํด์ค์ ์ถ๊ฐํ๋ฉด ํ๋กํ ํ์ ์ฒด์ธ์ ๋ฐ๋ผ ํ๋กํ ํ์ ํ๋กํผํฐ๋ฅผ ๊ฒ์ํ์ฌ ํ๋กํ ํ์ ํ๋กํผํฐ๋ฅผ ๋ฎ์ด์ฐ๋ ๊ฒ์ด ์๋๋ผ ์ธ์คํด์ค ํ๋กํผํฐ๋ก ์ถ๊ฐํ๋ค.
์ด์ฒ๋ผ ์์ ๊ด๊ณ์ ์ํด ํ๋กํผํฐ๊ฐ ๊ฐ๋ ค์ง๋ ํ์์ ํ๋กํผํฐ ์๋์
์ด๋ผ๊ณ ํ๋ค.
// 19-40
const Person = (function () {
function Person(name) {
this.name = name;
}
// 1. ์์ฑ์ ํจ์์ prototype ํ๋กํผํฐ๋ฅผ ํตํด ํ๋กํ ํ์
์ ๊ต์ฒด
Person.prototype = {
sayHello() {
console.log(`Hi My name is ${this.name}`);
}
};
return Person;
}());
const me = new Person('Lee');
1์์ Person.prototype์ ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ํ ๋นํ๋ค. ์ด๋ Person ์์ฑ์ ํจ์๊ฐ ์์ฑํ ๊ฐ์ฒด์ ํ๋กํ ํ์ ์ ๊ฐ์ฒด ๋ฆฌํฐ๋ด๋ก ๊ต์ฒดํ ๊ฒ์ด๋ค.
ํ๋กํ ํ์ ์ผ๋ก ๊ต์ฒดํ ๊ฐ์ฒด ๋ฆฌํฐ๋ด์๋ contructor ํ๋กํผํฐ๊ฐ ์๋ค. ํ๋กํ ํ์ ์ ๊ต์ฒดํ๋ฉด contructor ํ๋กํผํฐ์ ์์ฑ์ ํจ์ ๊ฐ์ ์ฐ๊ฒฐ์ด ํ๊ดด๋๋ค.
// 19-42
const Person = (function () {
function Person(name) {
this.name = name;
}
Person.prototype = {
// constructor ํ๋กํผํฐ์ ์์ฑ์ ํจ์ ๊ฐ์ ์ฐ๊ฒฐ ์ค์
constructor: Person,
sayHello() {
console.log(`Hi My name is ${this.name}`);
}
};
return Person;
}());
const me = new Person('Lee');
์ธ์คํด์ค์ __proto__
์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ํตํด ํ๋กํ ํ์
์ ๊ต์ฒดํ ์ ์๋ค.
// 19-43
function Person(name){
this.name = name;
}
const me = new Person('Lee');
const parent = {
sayhello(){
console.log(`My name is ${this.name}`);
}
}
// 1. me ๊ฐ์ฒด์ ํ๋กํ ํ์
์ parent ๊ฐ์ฒด๋ก ๊ตํํ๋ค.
Object.setPrototypeOf(me, parent);
// ์ ์ฝ๋๋ me.__proto__ = parent;์ ๊ฐ์ด ๋์
์ด๋ ์์ฑ์ ํจ์์ ์ํ ํ๋กํ ํ์ ์ ๊ต์ฒด์ ๋ง์ฐฌ๊ฐ์ง๋ก contructor ํ๋กํผํฐ๊ฐ ์๋ค.
์ด์ฒ๋ผ ํ๋กํ ํ์ ๊ต์ฒด๋ฅผ ํตํด ๊ฐ์ฒด ๊ฐ์ ์์ ๊ด๊ณ๋ฅผ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ ๊ฝค๋ ๋ฒ๊ฑฐ๋กญ๋ค. ๋ฐ๋ผ์ ํ๋กํ ํ์ ์ ์ง์ ๊ต์ฒดํ์ง ์๋ ๊ฒ์ด ์ข๋ค.
instanceof ์ฐ์ฐ์๋ ์ดํญ ์ฐ์ฐ์๋ก์ ์ข๋ณ์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ์๋ณ์, ์ฐ๋ณ์ ์์ฑ์ ํจ์๋ฅผ ๊ฐ๋ฆฌํค๋ ์๋ณ์๋ฅผ ํผ์ฐ์ฐ์๋ก ๋ฐ๋๋ค.(๊ฐ์ฒด instanceof ์์ฑ์ ํจ์
)
์ฐ๋ณ์ ์์ฑ์ ํจ์์ prototype์ ๋ฐ์ธ๋ฉ๋ ๊ฐ์ฒด๊ฐ ์ข๋ณ์ ๊ฐ์ฒด์ ํ๋กํ ํ์
์ฒด์ธ ์์ ์กด์ฌํ๋ฉด true
์๋๋ฉด false
๋ก ํ๊ฐ๋๋ค.
instanceof
contructor ํ๋กํผํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ์์ฑ์ ํจ์๋ฅผ ์ฐพ๋ ๊ฒ์ด ์๋๋ผ ์์ฑ์ ํจ์์ prototype์ ๋ฐ์ธ๋ฉ๋ ๊ฐ์ฒด๊ฐ ํ๋กํ ํ์
์ฒด์ธ ์์ ์กด์ฌํ๋์ง ํ์ธ
Object.create ๋ฉ์๋๋ ์ฒซ ๋ฒ์งธ ๋งค๊ฐ๋ณ์์ ์ ๋ฌํ ๊ฐ์ฒด์ ํ๋กํ ํ์ ์ฒด์ธ์ ์ํ๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค. ์ฆ, ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ฉด์ ์ง์ ์ ์ผ๋ก ์์์ ๊ตฌํํ๋ ๊ฒ์ด๋ค.
Object.create
์ฅ์
__proto__
์ ์ํ ์ง์ ์์// 19-55
const myProto = { x: 10 };
const obj = {
y: 20,
__proto__ : myProto
}
// obj => myPtoyo => Object.prototype => null
์ ์ ํ๋กํผํฐ/๋ฉ์๋๋ ์์ฑ์ ํจ์๋ก ์ธ์คํด์ค๋ฅผ ์์ฑํ์ง ์์๋ ์ฐธ์กฐ/ํธ์ถํ ์ ์๋ ํ๋กํผํฐ/๋ฉ์๋๋ฅผ ๋งํ๋ค. ์ด๊ฒ์ ์์ฑ์ ํจ์๊ฐ ์์ฑํ ์ธ์คํด์ค๋ก ์ฐธ์กฐ/ํธ์ถํ ์ ์๋ค.
// 19-56
// ์์ฑ์ ํจ์
function Person(name) {
this.name = name;
}
// ํ๋กํ ํ์
๋ฉ์๋
Person.prototype.sayHello = function () {
console.log(`Hi! My name is ${this.name}`);
};
// 1 ์ ์ ํ๋กํผํฐ
Person.staticProp = 'static prop';
// 2 ์ ์ ๋ฉ์๋
Person.staticMethod = function () {
console.log('staticMethod');
};
const me = new Person('Lee');
// ์์ฑ์ ํจ์์ ์ถ๊ฐํ ์ ์ ํ๋กํผํฐ/๋ฉ์๋๋ ์์ฑ์ ํจ์๋ก ์ฐธ์กฐ/ํธ์ถํ๋ค.
Person.staticMethod(); // staticMethod
// 3 ์ ์ ํ๋กํผํฐ/๋ฉ์๋๋ ์์ฑ์ ํจ์๊ฐ ์์ฑํ ์ธ์คํด์ค๋ก ์ฐธ์กฐ/ํธ์ถํ ์ ์๋ค.
// ์ธ์คํด์ค๋ก ์ฐธ์กฐ/ํธ์ถํ ์ ์๋ ํ๋กํผํฐ/๋ฉ์๋๋ ํ๋กํ ํ์
์ฒด์ธ ์์ ์กด์ฌํด์ผ ํ๋ค.
me.staticMethod(); // TypeError: me.staticMethod is not a function
Object.create
๊ฐ์ ๋ฉ์๋๋ ์ ์ ๋ฉ์๋์ด๊ณ , Object.prototype.hasOwnProperty
๊ฐ์ ๋ฉ์๋๋ ํ๋กํ ํ์
๋ฉ์๋์ด๋ค.
ํ๋กํ ํ์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ค๋ฉด ์ธ์คํด์ค๋ฅผ ์์ฑํด์ผ ํ์ง๋ง, ์ ์ ๋ฉ์๋๋ ์ธ์คํด์ค๋ฅผ ์์ฑํ์ง ์์๋ ํธ์ถํ ์ ์๋ค.
๊ฐ์ฒด ๋ด์ ํน์ ํ๋กํผํฐ๊ฐ ์กด์ฌํ๋์ง ์ฌ๋ถ๋ฅผ ํ์ธํ๋ค.
// 19-59
const person = {
name: 'Lee',
address: 'Seoul'
};
// person ๊ฐ์ฒด์ name ํ๋กํผํฐ๊ฐ ์กด์ฌํ๋ค.
console.log('name' in person); // true
// person ๊ฐ์ฒด์ address ํ๋กํผํฐ๊ฐ ์กด์ฌํ๋ค.
console.log('address' in person); // true
// person ๊ฐ์ฒด์ age ํ๋กํผํฐ๊ฐ ์กด์ฌํ์ง ์๋๋ค.
console.log('age' in person); // false
in ์ฐ์ฐ์ ๋์ ES6์์ ๋์ ๋ Reflect.has๋ฉ์๋๋ ์ฌ์ฉํ ์ ์๋ค. in๊ณผ ๋์ผํ๊ฒ ๋์ํ๋ค.
๊ฐ์ฒด์ ํน์ ํ๋กํผํฐ๊ฐ ์กด์ฌํ๋์ง ํ์ธํ ์ ์๋ค.
console.log(person.hasOwnProperty('name')); // true
console.log(person.hasOwnProperty('age')); // false
์ธ์๋ก ์ ๋ฌ๋ฐ์ ํ๋กํผํฐ ํค๊ฐ ๊ฐ์ฒด ๊ณ ์ ์ ํ๋กํผํฐ ํค์ธ ๊ฒฝ์ฐ์๋ง true๋ฅผ ๋ฐํํ๊ณ ์์๋ฐ์ ํ๋กํ ํ์ ์ ํค์ธ ๊ฒฝ์ฐ false๋ฅผ ๋ฐํํ๋ค.
for ... in ๋ฌธ์ ๊ฐ์ฒด์ ํ๋กํ ํ์
์ฒด์ธ ์์ ์กด์ฌํ๋ ๋ชจ๋ ํ๋กํ ํ์
์ ํ๋กํผํฐ ์ค์์ ํ๋กํผํฐ ์ดํธ๋ฆฌ๋ทฐํธ [[Enumerable]]์ ๊ฐ์ด true์ธ ํ๋กํผํฐ๋ฅผ ์ํํ๋ฉฐ ์ด๊ฑฐํ๋ค.
๊ทธ๋ฆฌ๊ณ ํ๋กํผํฐ ํค๊ฐ ์ฌ๋ฒ์ธ ํ๋กํผํฐ๋ ์ด๊ฑฐํ์ง ์๊ณ ํ๋กํผํฐ๋ฅผ ์ด๊ฑฐํ ๋ ์์๋ฅผ ๋ณด์ฅํ์ง ์์ผ๋ฏ๋ก ์ฃผ์ํด์ผํ๋ค.
for...in๋ฌธ์ ๊ฐ์ฒด ์์ ์ ๊ณ ์ ํ๋กํผํฐ ๋ฟ๋ง ์๋๋ผ ์์๋ฐ์ ํ๋กํผํฐ๋ ์ด๊ฑฐํ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๊ณ ์ ์ ํ๋กํผํฐ๋ง ์ด๊ฑฐํ๊ธฐ ์ํด์๋ Object.keys, Object.valeus, Object.entries ๋ฉ์๋ ์ฌ์ฉ์ ๊ถ์ฅํ๋ค.
1) Object.keys
๊ฐ์ฒด ์์ ์ ์ด๊ฑฐ๊ฐ๋ฅํ ํ๋กํผํฐ ํค๋ฅผ ๋ฐฐ์ด๋ก ๋ฐํํ๋ค.
// 19-72
const person = {
name: 'Lee',
address: 'Seoul',
__proto__: { age: 20 }
};
console.log(Object.keys(person)); // ["name", "address"]
2) Object.values
๊ฐ์ฒด ์์ ์ ์ด๊ฑฐ ๊ฐ๋ฅํ ํ๋กํผํฐ ๊ฐ์ ๋ฐฐ์ด๋ก ๋ฐํํ๋ค.
console.log(Object.values(person)); // ["Lee", "Seoul"]
3) Object.entries
๊ฐ์ฒด ์์ ์ ์ด๊ฑฐ ๊ฐ๋ฅํ ํ๋กํผํฐ ํค์ ๊ฐ์ ์์ ๋ฐฐ์ด์ ๋ฐฐ์ด์ ๋ด์ ๋ฐํํ๋ค.
console.log(Object.entries(person)); // [["name", "Lee"], ["address", "Seoul"]]
Object.entries(person).forEach(([key, value]) => console.log(key, value));
/*
name Lee
address Seoul
*/