๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Front-end/JS

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœํ† ํƒ€์ž… Prototype (2)

by ciocio 2022. 4. 4.

๐Ÿ“Œ ํ”„๋กœํ† ํƒ€์ž… (๊ฐ์ฒด) ?

 

โ— ๊ฐ์ฒด ๊ฐ„ ์ƒ์†inheritance์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ํ•ต์‹ฌ ๊ฐœ๋… โ—
โ— ํ”„๋กœํ† ํƒ€์ž…์˜ ํ”„๋กœํ† ํƒ€์ž…์€ ์–ธ์ œ๋‚˜ Object.prototype โ—
ํ”„๋กœํ† ํƒ€์ž…์€ ์–ด๋–ค ๊ฐ์ฒด์˜ ์ƒ์œ„ ๊ฐ์ฒด(๋ถ€๋ชจ ๊ฐ์ฒด)์˜ ์—ญํ• ์„ ํ•˜๋Š” ๊ฐ์ฒด๋กœ,
๋‹ค๋ฅธ ๊ฐ์ฒด์— ๊ณต์œ  ํ”„๋กœํผํ‹ฐ/๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

 

ํ”„๋กœํ† ํƒ€์ž…์„ ์ƒ์†๋ฐ›์€ ํ•˜์œ„ ๊ฐ์ฒด(์ž์‹ ๊ฐ์ฒด)๋Š” ์ƒ์œ„ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ/๋ฉ”์„œ๋“œ๋ฅผ
๋ณธ์ธ์˜ ํ”„๋กœํผํ‹ฐ/๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

๐Ÿ“Œ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐฉ์‹๊ณผ ํ”„๋กœํ† ํƒ€์ž… ๊ฒฐ์ •

 

๐Ÿ˜ฎ (์ง„์‹ฌ์œผ๋กœ ๋„ˆ๋ฌด ๋‹ค์–‘ํ•œ) ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐฉ๋ฒ•๋“ค ...
โœ” ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด
โœ” Object ์ƒ์„ฑ์ž ํ•จ์ˆ˜
โœ” ์ƒ์„ฑ์ž ํ•จ์ˆ˜ (new ์—ฐ์‚ฐ์ž)
โœ” Object.create ๋ฉ”์„œ๋“œ
โœ” ํด๋ž˜์Šค(ES6)

 

 

 ๐Ÿ“ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด 

๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์— ์˜ํ•ด ์ƒ์„ฑ๋˜๋Š” ๊ฐ์ฒด์˜ ํ”„๋กœํ† ํƒ€์ž…์€ Object.prototype ์ด๋‹ค.

 

const obj = {x: 1};

console.log(obj.constructor === Object);  // true
console.log(obj.hasOwnProperty('x'));     // true

// ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์— ์˜ํ•ด ์ƒ์„ฑ๋œ obj ๊ฐ์ฒด๋Š” Object.prototype ์„ ์ƒ์†๋ฐ›๋Š”๋‹ค.

 

 

 ๐Ÿ“ Object ์ƒ์„ฑ์ž ํ•จ์ˆ˜ 

Object ์ƒ์„ฑ์ž ํ•จ์ˆ˜์— ์˜ํ•ด ์ƒ์„ฑ๋˜๋Š” ๊ฐ์ฒด์˜ ํ”„๋กœํ† ํƒ€์ž…์€ Object.prototype ์ด๋‹ค.

 

const obj = new Object();
obj.x = 1;

console.log(obj.constructor === Object);  // true
console.log(obj.hasOwnProperty('x'));     // true

// Object ์ƒ์„ฑ์ž ํ•จ์ˆ˜์— ์˜ํ•ด ์ƒ์„ฑ๋œ obj ๊ฐ์ฒด๋Š” Object.prototype ์„ ์ƒ์†๋ฐ›๋Š”๋‹ค.
// ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด ๋ฐฉ์‹์€ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด ๋‚ด๋ถ€์— ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€๋งŒ
// Object ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ๋ฐฉ์‹์€ ์ผ๋‹จ ๋นˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ํ›„ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

 

 ๐Ÿ“ ์ƒ์„ฑ์ž ํ•จ์ˆ˜ (new ์—ฐ์‚ฐ์ž) 

์ƒ์„ฑ์ž ํ•จ์ˆ˜์— ์˜ํ•ด ์ƒ์„ฑ๋˜๋Š” ๊ฐ์ฒด์˜ ํ”„๋กœํ† ํƒ€์ž…์€
์ƒ์„ฑ์ž ํ•จ์ˆ˜์˜ prototype ํ”„๋กœํผํ‹ฐ์— ๋ฐ”์ธ๋”ฉ๋˜์–ด ์žˆ๋Š” ๊ฐ์ฒด๋‹ค.

 

function Person(name){
  this.name = name;
}

// ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ
Person.prototype.sayHello = function(){
  console.log(`Hi! My name is ${this.name}`);
};

const me = new Person('Lee');
const you = new Person('Kim');

me.sayHello();   // Hi! My name is Lee
you.sayHello();  // Hi! My name is Kim

// Person ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ๋ชจ๋“  ๊ฐ์ฒด๋Š”
// ํ”„๋กœํ† ํƒ€์ž…์— ์ถ”๊ฐ€๋œ sayHello ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์†๋ฐ›์•„ ์ž์‹ ์˜ ๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 ๐Ÿ“ Object.create ๋ฉ”์„œ๋“œ 

Object.create ๋ฉ”์„œ๋“œ๋Š” ํ”„๋กœํ† ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜์—ฌ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ.
Object.create ๋ฉ”์„œ๋“œ์˜ ์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜์—๋Š” ์ƒ์„ฑํ•  ๊ฐ์ฒด์˜ ํ”„๋กœํ† ํƒ€์ž…์œผ๋กœ ์ง€์ •ํ•  ๊ฐ์ฒด๋ฅผ,
๋‘ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜์—๋Š” ์ƒ์„ฑํ•  ๊ฐ์ฒด์˜ property key ์™€ property descriptor ๋กœ ์ด๋ค„์ง„ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌ.

 

// Object.create(prototype, [, propertiesObject])

// ์ง€์ •๋œ ํ”„๋กœํ† ํƒ€์ž… ๋ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๋Š” ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
// @param {Object} prototype - ์ƒ์„ฑํ•  ๊ฐ์ฒด์˜ ํ”„๋กœํ† ํƒ€์ž…์œผ๋กœ ์ง€์ •ํ•  ๊ฐ์ฒด
// @param {Object} [propertiesObject] - ์ƒ์„ฑํ•  ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๋Š” ๊ฐ์ฒด
// @returns {Object} ์ง€์ •๋œ ํ”„๋กœํ† ํƒ€์ž… ๋ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๋Š” ์ƒˆ๋กœ์šด ๊ฐ์ฒด

 

// obj → null
let obj = Object.create(null);
console.log(Object.getPrototypeOf(obj) === null);  // true
console.log(obj.toString());                       // Object.prototype์„ ์ƒ์†๋ฐ›์ง€ ๋ชปํ•จ.

// obj → Object.prototype → null
// obj = {}; ์™€ ๋™์ผ
obj = Object.create(Object.prototype);
console.log(Object.getPrototypeOf(obj) === Object.prototype);  // true

// obj → Object.prototype → null
// obj = {x: 1}; ์™€ ๋™์ผ
obj = Object.create(Object.prototype, {
  x: {value: 1, writable: true, enumerable: true, configurable: true}
});
// ์œ„ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๋™์ผํ•˜๋‹ค.
// obj = Object.create(Object.prototype);
// obj.x = 1;
console.log(obj.x);                                            // 1
console.log(Object.getPrototypeOf(obj) === Object.prototype);  // true

// obj → myProto → Object.prototype → null
// ์ž„์˜์˜ ๊ฐ์ฒด ์ง์ ‘ ์ƒ์†๋ฐ›๊ธฐ
const myProto = {x: 10};
obj = Object.create(myProto);
console.log(obj.x);                                            // 10
console.log(Object.getPrototypeOf(obj) === myProto);           // true

// obj → Person.prototype → Object.prototype → null
function Person(name){
  this.name = name;
}
obj = Object.create(Person.prototype);
obj.name = 'Lee';
console.log(obj.name);                                         // Lee
console.log(Object.getPrototypeOf(obj) === Person.prototype);  // true

 

 

๐Ÿ“Œ Object.prototype ?

 

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์˜ ์ข…์  (end of prototype chain)
Object.prototype ์˜ ํ”„๋กœํ† ํƒ€์ž…, ์ฆ‰ [[Prototype]] ๋‚ด๋ถ€ ์Šฌ๋กฏ์˜ ๊ฐ’์€ null ์ด๋‹ค.

 

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์˜ ์ข…์ ์— ์œ„์น˜ํ•˜๋Š” ๊ฐ์ฒด๋Š” Object.prototype ์˜ built-in ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค โ—

๊ทธ๋ž˜์„œ Object.prototype ์˜ built-in ๋ฉ”์„œ๋“œ๋Š” ๊ฐ„์ ‘์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

const obj = Object.create(null);
obj.a = 1;

// console.log(obj.hasOwnProperty('a'));
// TypeError: obj.hasOwnProperty is not a function

// Object.prototype์˜ built-in ๋ฉ”์„œ๋“œ๋Š” ๊ฐ„์ ‘์ ์œผ๋กœ ํ˜ธ์ถœํ•  ๊ฒƒ โ—
console.log(Object.prototype.hasOwnProperty.call(obj, 'a'));  // true

 

 

๐Ÿ“Œ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ vs ์Šค์ฝ”ํ”„ ์ฒด์ธ

 

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์€ ์ƒ์†๊ณผ ํ”„๋กœํผํ‹ฐ ๊ฒ€์ƒ‰์„ ์œ„ํ•œ ๋งค์ปค๋‹ˆ์ฆ˜
์Šค์ฝ”ํ”„ ์ฒด์ธ์€ ์‹๋ณ„์ž ๊ฒ€์ƒ‰์„ ์œ„ํ•œ ๋งค์ปค๋‹ˆ์ฆ˜
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์„ ๋”ฐ๋ผ ํ”„๋กœํผํ‹ฐ/๋ฉ”์„œ๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค.
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ์Šค์ฝ”ํ”„ ์ฒด์ธ์„ ๋”ฐ๋ผ ์‹๋ณ„์ž๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค.
ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ๊ณผ ์Šค์ฝ”ํ”„ ์ฒด์ธ์€ ์„œ๋กœ ํ˜‘๋ ฅํ•˜์—ฌ ํ”„๋กœํผํ‹ฐ์™€ ์‹๋ณ„์ž๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

 

 

๐Ÿ“Œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ๊ณผ ํ”„๋กœํผํ‹ฐ ์„€๋„์ž‰

 

๐Ÿ“ ์˜ค๋ฒ„๋ผ์ด๋”ฉ overriding

์ƒ์œ„ ํด๋ž˜์Šค๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ์žฌ์ •์˜ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹

 

๐Ÿ“ ํ”„๋กœํผํ‹ฐ ์„€๋„์ž‰ property shadowing

์ƒ์† ๊ด€๊ณ„์— ์˜ํ•ด ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ€๋ ค์ง€๋Š” ํ˜„์ƒ

 

const Person = (function(){
  // ์ƒ์„ฑ์ž ํ•จ์ˆ˜
  function Person(name){
    this.name = name;
  }

  // ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ
  Person.prototype.sayHi = function(){
    console.log(`Hi, my name is ${this.name}`);
  }

  // ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ๋ฐ˜ํ™˜
  return Person;
}());

const me = new Person('Lee');

// ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ
me.sayHi = function(){
  console.log(`Hey, my name is ${this.name}`);
};

me.sayHi();  // Hey, my name is Lee

// ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. 
// ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ๋Š” ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ์— ์˜ํ•ด ๊ฐ€๋ ค์ง„๋‹ค.

 

 

 

• ์ฐธ๊ณ  ์ž๋ฃŒ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ DEEP DIVE - ์ด์›…๋ชจ

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€