๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ Deep Dive ๋์์ 19์ฅ์ ์ ๋ฆฌํ์์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ ํ๋กํ ํ์ ๊ธฐ๋ฐ์ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ด๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ด๋ฃจ๊ณ ์๋ ๊ฑฐ์ ๋ชจ๋ ๊ฒ์ด ๊ฐ์ฒด์ด๋ค.
ํ๋ก๊ทธ๋จ์ ๋ช ๋ น์ด ๋๋ ํจ์์ ๋ชฉ๋ก์ผ๋ก ๋ณด๋ ์ ํต์ ์ธ ๋ช ๋ นํ ํ๋ก๊ทธ๋๋ฐ์ ์ ์์ฒ์ธ ๊ด์ ์์ ๋ฒ์ด๋ ์ฌ๋ฌ ๊ฐ์ ๋ ๋ฆฝ์ ๋จ์, ์ฆ ๊ฐ์ฒด์ ์งํฉ์ผ๋ก ํ๋ก๊ทธ๋จ์ ํํํ๋ ค๋ ํ๋ก๊ทธ๋๋ฐ ํจ๋ฌ๋ค์์ ๋งํ๋ค.
๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ์ค์ธ๊ณ์ ์ค์ฒด๋ฅผ ์ธ์ํ๋ ์ฒ ํ์ ์ฌ๊ณ ๋ฅผ ํ๋ก๊ทธ๋๋ฐ์ ์ ๋ชฉํ๋ ค๋ ์๋์์ ์์ํ๋ค. ์ค์ฒด๋ ํน์ง์ด๋ ์ฑ์ง์ ๋ํ๋ด๋ ์์ฑ์ ๊ฐ์ง๊ณ ์๊ณ , ์ด๋ฅผ ํตํด ์ค์ฒด๋ฅผ ์ธ์ํ๊ฑฐ๋ ๊ตฌ๋ณํ ์ ์๋ค. ์ด๋ฐ ์์ฑ๋ค ์ค์์ ํ๋ก๊ทธ๋จ์ ํ์ํ ์์ฑ์ ๊ฐ์ถ๋ ค ๋ด์ด ํํํ๋ ๊ฒ์ ์ถ์ํ๋ผ๊ณ ํ๋ค.
const person = {
name: 'Lee',
address: 'Seoul'
}
console.log(person); // {name:'Lee", address: 'Seoul'}
์ด์ฒ๋ผ ์์ฑ์ ํตํด ์ฌ๋ฌ ๊ฐ์ ๊ฐ์ ํ๋์ ๋จ์๋ก ๊ตฌ์ฑํ ๋ณตํฉ์ ์ธ ์๋ฃ๊ตฌ์กฐ๋ฅผ ๊ฐ์ฒด๋ผ ํ๋ค. ๊ฐ์ฒด๋ ์ํ์ ๋์์ ํ๋์ ๋ ผ๋ฆฌ์ ์ธ ๋จ์๋ก ๋ฌถ์ ์๋ฃ๊ตฌ์กฐ๋ผ๊ณ ๋ ํ ์ ์๋ค. ๊ฐ์ฒด์ ์ํ ๋ฐ์ดํฐ๋ฅผ ํ๋กํผํฐ, ๋์์ ๋ฉ์๋๋ผ ๋ถ๋ฅธ๋ค.
์์์ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ํต์ฌ ๊ฐ๋ ์ผ๋ก, ์ด๋ค ๊ฐ์ฒด์ ํ๋กํผํฐ ๋๋ ๋ฉ์๋๋ฅผ ๋ค๋ฅธ ๊ฐ์ฒด๊ฐ ์์๋ฐ์ ๊ทธ๋๋ก ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ๋งํ๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๋ ํ๋กํ ํ์ ์ ๊ธฐ๋ฐ์ผ๋ก ์์์ ๊ตฌํํ์ฌ ๋ถํ์ํ ์ค๋ณต์ ์ ๊ฑฐํ๋ค.
/// ์์ 19-03
function Circle(radius){
this.radius = radius;
this.getArea = function () {
return Math.PI * this.radius ** 2;
}
}
const circle1 = new Circle(1);
const circle2 = new Circle(2);
console.log(circle1.getArea === circle2.getArea); // false
์์ ์์ฑ์ ํจ์์์ getArea ๋ฉ์๋๋ ๋ชจ๋ ์ธ์คํด์ค๊ฐ ๋์ผํ ๋ด์ฉ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ๋จ ํ๋๋ง ์์ฑํ์ฌ ๋ชจ๋ ์ธ์คํด์ค๊ฐ ๊ณต์ ํด์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ฐ๋์งํ๋ค. ์ด๋ฌํ ๊ฒ์ ํ๋กํ ํ์ ์ ํตํด ๋ถํ์ํ ์ค๋ณต์ ์ ๊ฑฐํ ์ ์๋ค.
/// ์์ 19-04
function Circle(radius){
this.radius = radius;
}
// ํ๋กํ ํ์
์ Circle ์์ฑ์ ํจ์์ prototype ํ๋กํผํฐ์ ๋ฐ์ธ๋ฉ๋์ด ์๋ค.
Circle.prototype.getArea = function () {
return Math.PI * this.radius ** 2;
}
const circle1 = new Circle(1);
const circle2 = new Circle(2);
console.log(circle1.getArea === circle2.getArea); // true
Circle ์์ฑ์ ํจ์๊ฐ ์์ฑํ ๋ชจ๋ ์ธ์คํด์ค๋ ์์ ์ ํ๋กํ ํ์ , ์ฆ ์์(๋ถ๋ชจ) ๊ฐ์ฒด ์ญํ ์ ํ๋ Circle.prototype์ ๋ชจ๋ ํ๋กํผํฐ์ ๋ฉ์๋๋ฅผ ์์๋ฐ๋๋ค. ์์ ์ ์ํ๋ฅผ ๋ํ๋ด๋ radius ํ๊ณ ํผํฐ๋ง ๊ฐ๋ณ์ ์ผ๋ก ์์ ํ๊ณ ๋ด์ฉ์ด ๋์ผํ ๋ฉ์๋๋ ์์์ ํตํด ๊ณต์ ํ์ฌ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
๊ฐ์ฒด์งํฅ์ ํ๋ก๊ทธ๋๋ฐ ๊ทผ๊ฐ์ ์ด๋ฃจ๋ ๊ฐ์ฒด ๊ฐ ์์์ ๊ตฌํํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค. ๋ชจ๋ ๊ฐ์ฒด๋ [[Prototype]] ์ด๋ผ๋ ๋ด๋ถ ์ฌ๋กฏ์ ๊ฐ์ง๋ฉฐ, ์ด ๋ด๋ถ ์ฌ๋กฏ์ ๊ฐ์ ํ๋กํ ํ์ ์ ์ฐธ์กฐ๋ค(null์ธ ๊ฒฝ์ฐ๋ ์๋ค). [[Prototype]]์ ์ ์ฅ๋๋ ํ๋กํ ํ์ ์ ๊ฐ์ฒด ์์ฑ ๋ฐฉ์์ ์ํด ๊ฒฐ์ ๋๋ค. ์ฆ, ๊ฐ์ฒด๊ฐ ์์ฑ๋ ๋ ๊ฐ์ฒด ์์ฑ ๋ฐฉ์์ ๋ฐ๋ผ ํ๋กํ ํ์ ์ด ๊ฒฐ์ ๋๊ณ [[Prototype]]์ ์ ์ฅ๋๋ค.
๋ชจ๋ ๊ฐ์ฒด๋ __proto__
์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ํตํด ์์ ์ ํ๋กํ ํ์
, ์ฆ [[Prototype]] ๋ด๋ถ ์ฌ๋กฏ์ ๊ฐ์ ์ ์ผ๋ก ์ ๊ทผํ ์ ์๋ค.
__proto__
๋ ์ ๊ทผ์ ํ๋กํผํฐ๋ค.
__proto__
๋ getter/setter ํจ์๋ผ๊ณ ๋ถ๋ฅด๋ ์ ๊ทผ์ ํจ์๋ฅผ ํตํด ํ๋กํ ํ์
์ ์ทจ๋ํ๊ฑฐ๋ ํ ๋นํ๋ค. ๋ด๋ถ์ ์ผ๋ก __proto__
์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ํตํด ํ๋กํ ํ์
์ ์ ๊ทผํ๋ฉด getter [[Get]]์ด ํธ์ถ๋๊ณ ์๋ก์ด ํ๋กํ ํ์
์ ํ ๋นํ๋ฉด setter ํจ์์ธ [[Set]]์ด ํธ์ถ๋๋ค.
//์์ 19-06
const obj = {}
const parent = { x: 1};
// getter ํจ์์ธ get __proto__ ๊ฐ ํธ์ถ๋์ด obj ๊ฐ์ฒด์ ํ๋กํ ํ์
์ ์ทจ๋
obj.__proto__;
// setter ํจ์์ธ set __proto__ ๊ฐ ํธ์ถ๋์ด obj ๊ฐ์ฒด์ ํ๋กํ ํ์
์ ๊ต์ฒด
obj.__proto__ = parent;
console.log(obj.x); //1
__proto__
์ ๊ทผ์ ํ๋กํผํฐ๋ ์์์ ํตํด ์ฌ์ฉ๋๋ค.
__proto__
์ ๊ทผ์ ํ๋กํผํฐ๋ ๊ฐ์ฒด๊ฐ ์ง์ ์์ ํ๋ ํ๋กํผํฐ๊ฐ ์๋๋ผ Object.prototype์ ํ๋กํผํฐ๋ค. ๋ชจ๋ ๊ฐ์ฒด๋ ์์์ ํตํด Object.prototype.__proto__
์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
// ์์ 19-07
const person = { name: 'Lee'};
// person rorcpsms __proto__ ํ๋กํผํฐ๋ฅผ ์์ ํ์ง ์๋๋ค.
console.log(person.hasOwnProperty('__proto__')); //false
// ๋ชจ๋ ๊ฐ์ฒด๋ ์์์ ํตํด `Object.prototype.__proto__` ์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
console.log({}.__proto__ === Object.prototype); //true
__proto__
์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ํตํด ํ๋กํ ํ์
์ ์ ๊ทผํ๋ ์ด์
์ํธ ์ฐธ์กฐ์ ์ํด ํ๋กํ ํ์
์ฒด์ธ์ด ์์ฑ๋๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด์๋ค.
// ์์ 19-08
const parent = {};
const child = {};
// child์ ํ๋กํ ํ์
์ parent๋ก ์ค์
child.__proto__ = parent;
// parent์ ํ๋กํ ํ์
์ child๋ก ์ค์
parent.__proto__ = child; // TypeError: Cyclic __proto__ value
ํ๋กํ ํ์
์ฒด์ธ์ ๋จ๋ฐฉํฅ ๋ฆฌ์คํธ๋ก ๊ตฌํ๋์ด์ผ ํ๋ค. ์ฆ, ํ๋กํผํฐ ๊ฒ์ ๋ฐฉํฅ์ด ํ์ชฝ ๋ฐฉํฅ์ผ๋ก๋ง ํ๋ฌ๊ฐ์ผ ํ๋ค.
why? ์ํ ์ฐธ์กฐํ๋ ํ๋กํ ํ์
์ฒด์ธ์ด ๋ง๋ค์ด์ง๋ฉด ํ๋กํ ํ์
์ฒด์ธ ์ข
์ ์ด ์กด์ฌํ์ง ์๊ธฐ ๋๋ฌธ์ ํ๋กํ ํ์
์ฒด์ธ์์ ํ๋กํผํฐ๋ฅผ ๊ฒ์ํ ๋ ๋ฌดํ ๋ฃจํ์ ๋น ์ง๊ธฐ ๋๋ฌธ์
__proto__
์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ์ฝ๋ ๋ด์์ ์ง์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ์ง ์๋๋ค.
๋ชจ๋ ๊ฐ์ฒด๊ฐ __proto__
์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์๋๊ธฐ ๋๋ฌธ์๋ค. ์ง์ ์์์ ํตํด Object.prototype์ ์์๋ฐ์ง ์๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์๋ ์๊ธฐ ๋๋ฌธ์ __proto__
์ ๊ทผ์ ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค.
// ์์ 19-09
// obj๋ ํ๋กํ ํ์
์ฒด์ธ์ ์ข
์ ์ด๋ค. ๋ฐ๋ผ์ Object.__proto__๋ฅผ ์์๋ฐ์ ์ ์๋ค.
const obj = Object.create(null);
console.log(obj.__proto__); //undefined
// ๋ฐ๋ผ์ __proto__๋ณด๋ค Object.getPrototypeOf ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ํธ์ด ์ข๋ค.
console.log(Obj.getPrototypeOf(obj)); // null
const obj2 = {};
const parent = { x: 1};
Object.getPrototypeOf(obj2); // obj2.__proto__;
Object.setPrototypeOf(obj2, parent); //obj2.__proto__ = parent;
ํจ์ ๊ฐ์ฒด๋ง์ด ์์ ํ๋ prototypeํ๋กํผํฐ๋ ์์ฑ์ ํจ์๊ฐ ์์ฑํ ์ธ์คํด์ค์ ํ๋กํ ํ์ ์ ๊ฐ๋ฆฌํจ๋ค.
//์์ 19-11
// ํจ์ ๊ฐ์ฒด๋ prototype ํ๋กํผํฐ๋ฅผ ์์
(function () {}).hasOwnProperty('prototype'); //true
// ์ผ๋ฐ ๊ฐ์ฒด๋ prototype ํ๋กํผํฐ๋ฅผ ์์ ํ์ง ์๋๋ค.
(() {}).hasOwnProperty('prototype'); // false
์์ฑ์ ํจ์๋ก์ ํธ์ถํ ์ ์๋ ํจ์, ์ฆ non-constructor์ธ ํ์ดํ ํจ์์ ES6 ๋ฉ์๋ ์ถ์ฝ ํํ์ผ๋ก ์ ์ํ ๋ฉ์๋๋ prototype ํ๋กํผํฐ๋ฅผ ์์ ํ์ง ์์ผ๋ฉฐ ํ๋กํ ํ์ ๋ ์์ฑํ์ง ์๋๋ค.
๋ชจ๋ ๊ฐ์ฒด๊ฐ ๊ฐ์ง๊ณ ์๋ __proto__
์ ๊ทผ์ ํ๋กํผํฐ์ ํจ์ ๊ฐ์ฒด๋ง์ด ๊ฐ์ง๊ณ ์๋ prototype ํ๋กํผํฐ๋ ๊ฒฐ๊ตญ ๋์ผํ ํ๋กํ ํ์
์ ๊ฐ๋ฆฌํจ๋ค.
// ์์ 19-13
// ์์ฑ์ ํจ์
function Person(name){
this.name = name;
}
const me = new Person('Lee');
// ๊ฒฐ๊ตญ Person.prototype๊ณผ me.__proto__๋ ๊ฒฐ๊ตญ ๋์ผํ ํ๋กํ ํ์
์ ๊ฐ๋ฆฌํจ๋ค.
console.log(Person.prototype === me.__proto__); // true
๋ชจ๋ ํ๋กํ ํ์ ์ contructor ํ๋กํผํฐ๋ฅผ ๊ฐ๋๋ค. ์ด contructor ํ๋กํผํฐ๋ prototype ํ๋กํผํฐ๋ก ์์ ์ ์ฐธ์กฐํ๊ณ ์๋ ์์ฑ์ ํจ์๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
// ์์ 19-14
// ์์ฑ์ ํจ์
function Person(name){
this.name = name;
}
const me = new Person('Lee');
console.log(me.constructor === Person); // true
๋ฆฌํฐ๋ด ํ๊ธฐ๋ฒ์ ์ํ ๊ฐ์ฒด ์์ฑ ๋ฐฉ์๊ณผ ๊ฐ์ด ๋ช ์์ ์ผ๋ก new ์ฐ์ฐ์์ ํจ๊ป ์์ฑ์ ํจ์๋ฅผ ํธ์ถํ์ฌ ์ธ์คํด์ค๋ฅผ ์์ฑํ์ง ์๋ ๊ฐ์ฒด ์์ฑ ๋ฐฉ์๋ ์๋ค.
// ์์ 19-16 : ๋ฆฌํฐ๋ด๋ก ์์ฑ
// ๊ฐ์ฒด ๋ฆฌํฐ๋ด
const obj = {};
// ํจ์ ๋ฆฌํฐ๋ด
const add = function (a, b) { return a + b; };
// ๋ฐฐ์ด ๋ฆฌํฐ๋ด
const arr = [1, 2, 3];
// ์ ๊ทํํ์ ๋ฆฌํฐ๋ด
const regexp = /is/ig;
๋ฆฌํฐ๋ด ํ๊ธฐ๋ฒ์ ์ํด ์์ฑ๋ ๊ฐ์ฒด๋ ๋ฌผ๋ก ํ๋กํ ํ์ ์ด ์กด์ฌํ๋ค. ํ์ง๋ง ์ด๋ฐ ๊ฐ์ฒด๋ constructorํ๋กํผํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ์์ฑ์ ํจ์๊ฐ ๋ฐ๋์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ํจ์๋ผ๊ณ ๋จ์ ํ ์ ์๋ค.
// obj ๊ฐ์ฒด๋ Object ์์ฑ์ ํจ์๋ก ์์ฑํ ๊ฐ์ฒด๊ฐ ์๋๋ผ ๊ฐ์ฒด ๋ฆฌํฐ๋ด๋ก ์์ฑํ๋ค.
const obj = {};
// ํ์ง๋ง obj ๊ฐ์ฒด์ ์์ฑ์ ํจ์๋ Object ์์ฑ์ ํจ์๋ค.
console.log(obj.constructor === Object); // true
๊ฒฐ๊ณผ์ ์ผ๋ก ๋ฆฌํฐ๋ด๋ก ์์ฑํ ๊ฐ์ฒด์ ์์ฑ์ ํจ์๋ก ์์ฑํ ๊ฐ์ฒด์ constructorํ๋กํผํฐ๋ฅผ ํ์ธํ๋ฉด ๋์ผํด ๋ณด์ด์ง๋ง ๊ฐ์ฒด๊ฐ ์์ฑ๋๋ ๋ฐฉ์์ ๋ค๋ฅด๋ค.
์์ ์ฌ์ง์์ 2๋ฒ์ ๋ณด๋ฉด ์์ฑ์ ํจ์์ ์ธ์๋ฅผ ์ ๋ฌํ์ง ์๊ฑฐ๋ undefined, null์ ์ธ์๋ก ์ ๋ฌํ์ฌ ํธ์ถํ๋ฉด ์ถ์ ์ฐ์ฐ OrdinaryObjectCreate๋ฅผ ํธ์ถํ์ฌ Object.prototype์ ํ๋กํ ํ์ ์ผ๋ก ๊ฐ๋ ๋น ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
// ์์ 19-18
// 1. new.target์ด undefined๋ Object๊ฐ ์๋ ๊ฒฝ์ฐ
// ์ธ์คํด์ค -> Foo.prototype -> Object.prototype ์์ผ๋ก ํ๋กํ ํ์
์ฒด์ธ์ด ์์ฑ๋๋ค.
class Foo extends Object {}
new Foo(); // Foo {}
// 2. Object ์์ฑ์ ํจ์์ ์ํ ๊ฐ์ฒด ์์ฑ
// Object ์์ฑ์ ํจ์๋ new ์ฐ์ฐ์์ ํจ๊ป ํธ์ถํ์ง ์์๋ new ์ฐ์ฐ์์ ํจ๊ป ํธ์ถํ ๊ฒ๊ณผ ๋์ผํ๊ฒ ๋์ํ๋ค.
// ์ธ์๊ฐ ์ ๋ฌ๋์ง ์์์ ๋ ์ถ์ ์ฐ์ฐ OrdinaryObjectCreate๋ฅผ ํธ์ถํ์ฌ ๋น ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
let obj = new Object();
console.log(obj); // {}
// 3. ์ธ์๊ฐ ์ ๋ฌ๋ ๊ฒฝ์ฐ์๋ ์ธ์๋ฅผ ๊ฐ์ฒด๋ก ๋ณํํ๋ค.
// Number ๊ฐ์ฒด ์์ฑ
obj = new Object(123);
console.log(obj); // Number {123}
// String ๊ฐ์ฒด ์์ฑ
obj = new Object('123');
console.log(obj); // String {"123"}
๊ฐ์ฒด ๋ฆฌํฐ๋ด์ด ํ๊ฐ๋ ๋์๋ ์ ์ฐ์ฐ OrdinaryObjectCreate๋ฅผ ํธ์ถํ์ฌ ๋น ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ํ๋กํผํฐ๋ฅผ ์ถ๊ฐํ๋๋ก ์ ์๋์ด ์๋ค.
์ด์ฒ๋ผ Object ์์ฑ์ ํจ์ ํธ์ถ๊ณผ ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ํ๊ฐ๋ ์ถ์ ์ฐ์ฐ OrdinaryObjectCreate๋ฅผ ํธ์ถํ์ฌ ๋น ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ์ ์์ ๋์ผํ๋, new.target์ ํ์ธ์ด๋ ํ๋กํผํฐ๋ฅผ ์ถ๊ฐํ๋ ์ฒ๋ฆฌ ๋ฑ ์ธ๋ถ ๋ด์ฉ์ ๋ค๋ฅด๋ค.
๋ฐ๋ผ์ ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ์ํด ์์ฑ๋ ๊ฐ์ฒด๋ Object์์ฑ์ ํจ์๊ฐ ์์ฑํ ๊ฐ์ฒด๊ฐ ์๋๋ค.