์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹ ์™„๋ฒฝ ๊ฐ€์ด๋“œ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹ ์™„๋ฒฝ ๊ฐ€์ด๋“œ

D
dongAuthor
11 min read

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์˜ ํ•ต์‹ฌ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค์ „ ํ™œ์šฉ๊นŒ์ง€! ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ ์ธ ์ƒ์† ๊ตฌ์กฐ์™€ prototype, proto ์ฐจ์ด์ ์„ ์ฝ”๋“œ ์˜ˆ์ œ๋กœ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ๋ฐ˜๋“œ์‹œ ์ดํ•ดํ•ด์•ผ ํ•  ๊ฐœ๋… ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์ž…๋‹ˆ๋‹ค. ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์ด๋ฉฐ, ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด์š”.

๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด ES6 ํด๋ž˜์Šค ๋ฌธ๋ฒ•์— ์ต์ˆ™ํ•ด์ง€๋ฉด์„œ ํ”„๋กœํ† ํƒ€์ž…์˜ ์ค‘์š”์„ฑ์„ ๊ฐ„๊ณผํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํด๋ž˜์Šค ๋ฌธ๋ฒ•๋„ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ํ”„๋กœํ† ํƒ€์ž…์„ ํ™œ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์„ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๋ฉด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋™์ž‘ ์›๋ฆฌ๋ฅผ ๋” ๊นŠ์ด ์žˆ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์–ด์š”.

์ด ๊ธ€์—์„œ๋Š” ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค์ œ ํ™œ์šฉ ๋ฐฉ๋ฒ•๊นŒ์ง€, ์‹ค๋ฌด์—์„œ ๋ฐ”๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋‚ด์šฉ๋“ค์„ ๋‹ค๋ค„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ๋‹จ๊ณ„๋ณ„๋กœ ์„ค๋ช…๋“œ๋ฆด ํ…Œ๋‹ˆ, ๋๊นŒ์ง€ ๋”ฐ๋ผ์˜ค์‹œ๋ฉด ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹ ๋งˆ์Šคํ„ฐ๊ฐ€ ๋  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”!

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๋งŒ๋‚จ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋‹ค์ค‘ ํŒจ๋Ÿฌ๋‹ค์ž„ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ๋„ ๊ฐ€๋Šฅํ•˜๊ณ , ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๋„ ์ง€์›ํ•˜์ฃ . ํ•˜์ง€๋งŒ ์ž๋ฐ”๋‚˜ C++๊ณผ ๊ฐ™์€ ์ „ํ†ต์ ์ธ ๊ฐ์ฒด ์ง€ํ–ฅ ์–ธ์–ด์™€๋Š” ๋‹ค๋ฅธ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ด์š”.

์ „ํ†ต์ ์ธ ๊ฐ์ฒด ์ง€ํ–ฅ ์–ธ์–ด๋“ค์€ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ์ƒ์†์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํด๋ž˜์Šค๋ผ๋Š” ์„ค๊ณ„๋„๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ ์„ค๊ณ„๋„๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด์ฃ . ๋ฐ˜๋ฉด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ƒ์†์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

// ์ „ํ†ต์ ์ธ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ์–ธ์–ด์˜ ๊ฐœ๋… (์‹ค์ œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋Š” ์•„๋‹˜)
class Animal {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(`${this.name}๊ฐ€ ์†Œ๋ฆฌ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค.`);
  }
}

// ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ ‘๊ทผ
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(`${this.name}๊ฐ€ ์†Œ๋ฆฌ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค.`);
};

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ ์ง์ ‘ ์ƒ์†๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์ด์—์š”.

ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€?

ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํด๋ž˜์Šค ์—†์ด๋„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ƒ์†์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจ๋Ÿฌ๋‹ค์ž„์ž…๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋ชจ๋“  ๊ฐ์ฒด๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋Š” ์ˆจ๊ฒจ์ง„ ๋งํฌ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์š”.

ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํŠน์ง•

  1. ๋™์  ์ƒ์†: ์‹คํ–‰ ์‹œ๊ฐ„์— ๊ฐ์ฒด์˜ ํ”„๋กœํ† ํƒ€์ž…์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์œ ์—ฐ์„ฑ: ํด๋ž˜์Šค ์„ ์–ธ ์—†์ด๋„ ๊ฐ์ฒด ๊ฐ„ ์ƒ์† ๊ด€๊ณ„๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”.
  3. ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ: ๊ณตํ†ต ๋ฉ”์„œ๋“œ๋ฅผ ํ”„๋กœํ† ํƒ€์ž…์—์„œ ๊ณต์œ ํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
// ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ƒ์† ์˜ˆ์ œ
const animal = {
  type: '๋™๋ฌผ',
  speak() {
    console.log(`${this.name}๋Š” ${this.type}์ž…๋‹ˆ๋‹ค.`);
  }
};

const dog = Object.create(animal);
dog.name = '๋ฉ๋ฉ์ด';
dog.breed = '์ง„๋—๊ฐœ';

dog.speak(); // "๋ฉ๋ฉ์ด๋Š” ๋™๋ฌผ์ž…๋‹ˆ๋‹ค."

์ด ๋ฐฉ์‹์˜ ์žฅ์ ์€ ๋งค์šฐ ์œ ์—ฐํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•„์š”์— ๋”ฐ๋ผ ๊ฐ์ฒด์˜ ๊ตฌ์กฐ๋ฅผ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๊ณ , ๋ณต์žกํ•œ ํด๋ž˜์Šค ๊ณ„์ธต ๊ตฌ์กฐ ์—†์ด๋„ ์ƒ์†์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด์š”.

ํ•จ์ˆ˜์˜ prototype ํ”„๋กœํผํ‹ฐ ๊นŠ์ด ํŒŒํ—ค์น˜๊ธฐ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ํ•จ์ˆ˜๋Š” ํŠน๋ณ„ํ•œ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ํ•จ์ˆ˜๋Š” prototype์ด๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์š”. ์ด prototype ํ”„๋กœํผํ‹ฐ๋Š” ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ์ž๋กœ ์‚ฌ์šฉ๋  ๋•Œ ๋งŒ๋“ค์–ด์ง€๋Š” ๊ฐ์ฒด๋“ค์ด ์ƒ์†๋ฐ›์„ ํ”„๋กœํ† ํƒ€์ž… ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.

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

console.log(Person.prototype); // {constructor: ฦ’}
console.log(typeof Person.prototype); // "object"

ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ์ž๋™์œผ๋กœ ํ•ด๋‹น ํ•จ์ˆ˜์˜ prototype ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ด ํ”„๋กœํ† ํƒ€์ž… ๊ฐ์ฒด๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ constructor ํ”„๋กœํผํ‹ฐ๋งŒ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์š”.

prototype ํ”„๋กœํผํ‹ฐ ํ™œ์šฉํ•˜๊ธฐ

prototype ํ”„๋กœํผํ‹ฐ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋กœ ๋งŒ๋“  ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ์™€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function Car(brand, model) {
  this.brand = brand;
  this.model = model;
}

// ํ”„๋กœํ† ํƒ€์ž…์— ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
Car.prototype.getInfo = function() {
  return `${this.brand} ${this.model}`;
};

Car.prototype.start = function() {
  console.log(`${this.getInfo()}์˜ ์‹œ๋™์„ ์ผญ๋‹ˆ๋‹ค.`);
};

const myCar = new Car('ํ˜„๋Œ€', '์†Œ๋‚˜ํƒ€');
const yourCar = new Car('๊ธฐ์•„', 'K5');

myCar.start(); // "ํ˜„๋Œ€ ์†Œ๋‚˜ํƒ€์˜ ์‹œ๋™์„ ์ผญ๋‹ˆ๋‹ค."
yourCar.start(); // "๊ธฐ์•„ K5์˜ ์‹œ๋™์„ ์ผญ๋‹ˆ๋‹ค."

// ๋‘ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ณต์œ ํ•˜๋Š”์ง€ ํ™•์ธ
console.log(myCar.start === yourCar.start); // true

์ด ๋ฐฉ์‹์˜ ํฐ ์žฅ์ ์€ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ฐ ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ์ •์˜ํ•œ๋‹ค๋ฉด, ์ธ์Šคํ„ด์Šค ๊ฐœ์ˆ˜๋งŒํผ ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์ƒ์„ฑ๋˜๊ฒ ์ฃ . ํ•˜์ง€๋งŒ ํ”„๋กœํ† ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์–ด์š”.

__proto__์™€ [[Prototype]] ๋‚ด๋ถ€ ์Šฌ๋กฏ ์ดํ•ดํ•˜๊ธฐ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋ชจ๋“  ๊ฐ์ฒด๋Š” [[Prototype]]์ด๋ผ๋Š” ๋‚ด๋ถ€ ์Šฌ๋กฏ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ•ด๋‹น ๊ฐ์ฒด์˜ ํ”„๋กœํ† ํƒ€์ž…์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ˆจ๊ฒจ์ง„ ๋งํฌ์˜ˆ์š”. ๋งŽ์€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ด ๋‚ด๋ถ€ ์Šฌ๋กฏ์— __proto__๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

__proto__์™€ prototype์˜ ์ฐจ์ด์ 

์ด ๋‘˜์„ ํ˜ผ๋™ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์€๋ฐ, ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•ด์š”.

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

const dog = new Animal('๋ฉ๋ฉ์ด');

// prototype: ํ•จ์ˆ˜์˜ ํ”„๋กœํผํ‹ฐ (์ƒ์„ฑ์ž ํ•จ์ˆ˜์—๋งŒ ์กด์žฌ)
console.log(Animal.prototype); // {constructor: ฦ’}

// __proto__: ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ (๋ชจ๋“  ๊ฐ์ฒด์— ์กด์žฌ)
console.log(dog.__proto__); // {constructor: ฦ’}

// ์ด ๋‘˜์€ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค
console.log(Animal.prototype === dog.__proto__); // true

์‹ค์ œ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ ํ™•์ธํ•˜๊ธฐ

function Shape(type) {
  this.type = type;
}

Shape.prototype.getType = function() {
  return this.type;
};

function Circle(radius) {
  Shape.call(this, '์›');
  this.radius = radius;
}

// Circle์ด Shape์„ ์ƒ์†๋ฐ›๋„๋ก ์„ค์ •
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;

Circle.prototype.getArea = function() {
  return Math.PI * this.radius * this.radius;
};

const myCircle = new Circle(5);

// ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ ํ™•์ธ
console.log(myCircle.__proto__ === Circle.prototype); // true
console.log(myCircle.__proto__.__proto__ === Shape.prototype); // true
console.log(myCircle.__proto__.__proto__.__proto__ === Object.prototype); // true

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์˜ ๋™์ž‘ ์›๋ฆฌ

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋‚˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ฐพ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. ํ•ด๋‹น ๊ฐ์ฒด์— ์›ํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ์—†์œผ๋ฉด, ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์„ ๋”ฐ๋ผ ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ์ฐพ์•„์š”.

ํ”„๋กœํผํ‹ฐ ๊ฒ€์ƒ‰ ๊ณผ์ •

  1. ๋จผ์ € ๊ฐ์ฒด ์ž์‹ ์˜ ํ”„๋กœํผํ‹ฐ์—์„œ ๊ฒ€์ƒ‰
  2. ์—†์œผ๋ฉด __proto__๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ”„๋กœํ† ํƒ€์ž… ๊ฐ์ฒด์—์„œ ๊ฒ€์ƒ‰
  3. ์—ฌ์ „ํžˆ ์—†์œผ๋ฉด ๊ทธ ํ”„๋กœํ† ํƒ€์ž…์˜ ํ”„๋กœํ† ํƒ€์ž…์—์„œ ๊ฒ€์ƒ‰
  4. Object.prototype๊นŒ์ง€ ์˜ฌ๋ผ๊ฐ€์„œ๋„ ์—†์œผ๋ฉด undefined ๋ฐ˜ํ™˜
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(`${this.name}๊ฐ€ ์†Œ๋ฆฌ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค.`);
};

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  console.log('๋ฉ๋ฉ!');
};

const myDog = new Dog('๋ฐ”๋‘‘์ด', '์ง„๋—๊ฐœ');

// ํ”„๋กœํผํ‹ฐ ๊ฒ€์ƒ‰ ๊ณผ์ • ์‹œ๋ฎฌ๋ ˆ์ด์…˜
console.log(myDog.name); // 1๋‹จ๊ณ„: myDog ๊ฐ์ฒด์—์„œ ์ฐพ์Œ - "๋ฐ”๋‘‘์ด"
console.log(myDog.breed); // 1๋‹จ๊ณ„: myDog ๊ฐ์ฒด์—์„œ ์ฐพ์Œ - "์ง„๋—๊ฐœ"
myDog.bark(); // 2๋‹จ๊ณ„: Dog.prototype์—์„œ ์ฐพ์Œ - "๋ฉ๋ฉ!"
myDog.speak(); // 3๋‹จ๊ณ„: Animal.prototype์—์„œ ์ฐพ์Œ - "๋ฐ”๋‘‘์ด๊ฐ€ ์†Œ๋ฆฌ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค."
console.log(myDog.toString()); // 4๋‹จ๊ณ„: Object.prototype์—์„œ ์ฐพ์Œ

๋™์  ํ”„๋กœํ† ํƒ€์ž… ๋ณ€๊ฒฝ

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

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

const user1 = new User('๊น€์ฒ ์ˆ˜');
const user2 = new User('์ด์˜ํฌ');

// ๋‚˜์ค‘์— ํ”„๋กœํ† ํƒ€์ž…์— ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
User.prototype.greet = function() {
  console.log(`์•ˆ๋…•ํ•˜์„ธ์š”, ${this.name}์ž…๋‹ˆ๋‹ค.`);
};

// ์ด๋ฏธ ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋“ค๋„ ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
user1.greet(); // "์•ˆ๋…•ํ•˜์„ธ์š”, ๊น€์ฒ ์ˆ˜์ž…๋‹ˆ๋‹ค."
user2.greet(); // "์•ˆ๋…•ํ•˜์„ธ์š”, ์ด์˜ํฌ์ž…๋‹ˆ๋‹ค."

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์˜ ์ œ์•ฝ์‚ฌํ•ญ๊ณผ ์ฃผ์˜์ 

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์€ ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๋ช‡ ๊ฐ€์ง€ ์ œ์•ฝ์‚ฌํ•ญ๊ณผ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ๋“ค์ด ์žˆ์–ด์š”.

์ˆœํ™˜ ์ฐธ์กฐ ๋ฐฉ์ง€

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์—์„œ ์ˆœํ™˜ ์ฐธ์กฐ๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

const obj1 = {};
const obj2 = {};

obj1.__proto__ = obj2;
// obj2.__proto__ = obj1; // TypeError: Cyclic __proto__ value

์„ฑ๋Šฅ ๊ณ ๋ ค์‚ฌํ•ญ

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์ด ๊ธธ์–ด์งˆ์ˆ˜๋ก ํ”„๋กœํผํ‹ฐ ๊ฒ€์ƒ‰ ์‹œ๊ฐ„์ด ๋Š˜์–ด๋‚ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์ž์ฃผ ์ ‘๊ทผํ•˜๋Š” ํ”„๋กœํผํ‹ฐ์˜ ๊ฒฝ์šฐ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์–ด์š”.

// ์„ฑ๋Šฅ์„ ์œ„ํ•œ ์บ์‹ฑ ์˜ˆ์ œ
function ExpensiveOperation() {}

ExpensiveOperation.prototype.calculate = function() {
  if (this._cachedResult) {
    return this._cachedResult;
  }
  
  // ๋ณต์žกํ•œ ๊ณ„์‚ฐ ์ˆ˜ํ–‰
  this._cachedResult = Math.random() * 1000;
  return this._cachedResult;
};

const operation = new ExpensiveOperation();
console.log(operation.calculate()); // ์ฒซ ๋ฒˆ์งธ ํ˜ธ์ถœ: ๊ณ„์‚ฐ ์ˆ˜ํ–‰
console.log(operation.calculate()); // ๋‘ ๋ฒˆ์งธ ํ˜ธ์ถœ: ์บ์‹œ๋œ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜

ํ”„๋กœํผํ‹ฐ ์ˆ˜์ •๊ณผ ์‚ญ์ œ ์ œํ•œ

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์„ ํ†ตํ•ด ์ ‘๊ทผํ•œ ํ”„๋กœํผํ‹ฐ๋Š” ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•˜๊ณ , ์ˆ˜์ •์ด๋‚˜ ์‚ญ์ œ๋Š” ํ•ด๋‹น ๊ฐ์ฒด์— ์ง์ ‘์ ์œผ๋กœ ์ž‘์šฉํ•ฉ๋‹ˆ๋‹ค.

const parent = { x: 1 };
const child = Object.create(parent);

console.log(child.x); // 1 (parent์—์„œ ์ƒ์†)

child.x = 2; // child ๊ฐ์ฒด์— ์ƒˆ๋กœ์šด x ํ”„๋กœํผํ‹ฐ ์ƒ์„ฑ
console.log(child.x); // 2
console.log(parent.x); // 1 (๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Œ)

delete child.x;
console.log(child.x); // 1 (๋‹ค์‹œ parent์—์„œ ์ƒ์†)

ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ vs ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ƒ์† ๋น„๊ต

ES6์—์„œ ๋„์ž…๋œ ํด๋ž˜์Šค ๋ฌธ๋ฒ•๊ณผ ์ „ํ†ต์ ์ธ ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ƒ์†์„ ๋น„๊ตํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šค ๋ฌธ๋ฒ• (ES6+)

class Animal {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(`${this.name}๊ฐ€ ์†Œ๋ฆฌ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค.`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
  
  bark() {
    console.log('๋ฉ๋ฉ!');
  }
}

const myDog = new Dog('๋ฐ”๋‘‘์ด', '์ง„๋—๊ฐœ');

ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ๊ตฌํ˜„

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

Animal.prototype.speak = function() {
  console.log(`${this.name}๊ฐ€ ์†Œ๋ฆฌ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค.`);
};

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  console.log('๋ฉ๋ฉ!');
};

const myDog = new Dog('๋ฐ”๋‘‘์ด', '์ง„๋—๊ฐœ');

๊ฐ ๋ฐฉ์‹์˜ ์žฅ๋‹จ์ 

ํด๋ž˜์Šค ๋ฌธ๋ฒ•์˜ ์žฅ์ :

  • ๋ฌธ๋ฒ•์ด ์ง๊ด€์ ์ด๊ณ  ์ฝ๊ธฐ ์‰ฌ์›€
  • ๋‹ค๋ฅธ ๊ฐ์ฒด ์ง€ํ–ฅ ์–ธ์–ด์™€ ์œ ์‚ฌํ•œ ๊ตฌ์กฐ
  • super ํ‚ค์›Œ๋“œ๋กœ ๋ถ€๋ชจ ํด๋ž˜์Šค ์ ‘๊ทผ์ด ๊ฐ„ํŽธ

ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜์˜ ์žฅ์ :

  • ๋” ์œ ์—ฐํ•œ ์ƒ์† ๊ตฌ์กฐ
  • ๋Ÿฐํƒ€์ž„์— ๋™์ ์œผ๋กœ ์ƒ์† ๊ด€๊ณ„ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
  • ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ์„ ๋” ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ด ๊ฐ€๋Šฅ

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์˜ ์‹ค์šฉ์  ์ด์ 

๋ฉ”๋ชจ๋ฆฌ ์ ˆ์•ฝ๊ณผ ์„ฑ๋Šฅ ์ตœ์ ํ™”

ํ”„๋กœํ† ํƒ€์ž…์„ ํ™œ์šฉํ•˜๋ฉด ๋ฉ”์„œ๋“œ๋ฅผ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ ํ•˜๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.

// ๋น„ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•
function User(name) {
  this.name = name;
  this.greet = function() { // ๊ฐ ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ํ•จ์ˆ˜ ์ƒ์„ฑ
    console.log(`์•ˆ๋…•ํ•˜์„ธ์š”, ${this.name}์ž…๋‹ˆ๋‹ค.`);
  };
}

// ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•
function User(name) {
  this.name = name;
}

User.prototype.greet = function() { // ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ 
  console.log(`์•ˆ๋…•ํ•˜์„ธ์š”, ${this.name}์ž…๋‹ˆ๋‹ค.`);
};

// ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋น„๊ต
const users1 = Array(1000).fill().map((_, i) => new User(`์‚ฌ์šฉ์ž${i}`));
// ์ฒซ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•: 1000๊ฐœ์˜ greet ํ•จ์ˆ˜๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์ƒ์„ฑ
// ๋‘ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•: 1๊ฐœ์˜ greet ํ•จ์ˆ˜๋ฅผ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ 

์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ ํ–ฅ์ƒ

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์„ ํ™œ์šฉํ•˜๋ฉด ๊ณตํ†ต ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ๊ณตํ†ต ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ ๊ธฐ๋ณธ ํด๋ž˜์Šค
function BaseEntity() {}

BaseEntity.prototype.save = function() {
  console.log(`${this.constructor.name}์„(๋ฅผ) ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.`);
};

BaseEntity.prototype.delete = function() {
  console.log(`${this.constructor.name}์„(๋ฅผ) ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.`);
};

// ํŠนํ™”๋œ ํด๋ž˜์Šค๋“ค
function User(name) {
  this.name = name;
}
User.prototype = Object.create(BaseEntity.prototype);
User.prototype.constructor = User;

function Product(name, price) {
  this.name = name;
  this.price = price;
}
Product.prototype = Object.create(BaseEntity.prototype);
Product.prototype.constructor = Product;

const user = new User('๊น€์ฒ ์ˆ˜');
const product = new Product('๋…ธํŠธ๋ถ', 1000000);

user.save(); // "User์„(๋ฅผ) ์ €์žฅํ•ฉ๋‹ˆ๋‹ค."
product.delete(); // "Product์„(๋ฅผ) ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค."

ํ”„๋กœํ† ํƒ€์ž… ๊ด€๋ฆฌ ๋ฉ”์„œ๋“œ๋“ค

Object.getPrototypeOf์™€ Object.setPrototypeOf

์ด ๋ฉ”์„œ๋“œ๋“ค์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด์˜ ํ”„๋กœํ† ํƒ€์ž…์„ ์•ˆ์ „ํ•˜๊ฒŒ ์กฐํšŒํ•˜๊ณ  ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์–ด์š”.

const animal = {
  type: '๋™๋ฌผ',
  speak() {
    console.log(`${this.name}๋Š” ${this.type}์ž…๋‹ˆ๋‹ค.`);
  }
};

const dog = { name: '๋ฉ๋ฉ์ด' };

// ํ”„๋กœํ† ํƒ€์ž… ์„ค์ •
Object.setPrototypeOf(dog, animal);

// ํ”„๋กœํ† ํƒ€์ž… ์กฐํšŒ
console.log(Object.getPrototypeOf(dog) === animal); // true

dog.speak(); // "๋ฉ๋ฉ์ด๋Š” ๋™๋ฌผ์ž…๋‹ˆ๋‹ค."

Object.create ํ™œ์šฉํ•˜๊ธฐ

Object.create๋Š” ์ง€์ •๋œ ํ”„๋กœํ† ํƒ€์ž…์„ ๊ฐ€์ง„ ์ƒˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฐ€์žฅ ๊น”๋”ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

const vehiclePrototype = {
  start() {
    console.log(`${this.brand} ${this.model}์˜ ์‹œ๋™์„ ์ผญ๋‹ˆ๋‹ค.`);
  },
  
  stop() {
    console.log(`${this.brand} ${this.model}์˜ ์‹œ๋™์„ ๋•๋‹ˆ๋‹ค.`);
  }
};

// ํ”„๋กœํ† ํƒ€์ž…์„ ์ง€์ •ํ•˜์—ฌ ๊ฐ์ฒด ์ƒ์„ฑ
const car = Object.create(vehiclePrototype, {
  brand: { value: 'ํ˜„๋Œ€', writable: true },
  model: { value: '์†Œ๋‚˜ํƒ€', writable: true },
  year: { value: 2023, writable: true }
});

car.start(); // "ํ˜„๋Œ€ ์†Œ๋‚˜ํƒ€์˜ ์‹œ๋™์„ ์ผญ๋‹ˆ๋‹ค."

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ ์•ˆ์ „ํ•˜๊ฒŒ ํƒ์ƒ‰ํ•˜๊ธฐ

function walkPrototypeChain(obj) {
  const chain = [];
  let current = obj;
  
  while (current !== null) {
    chain.push(current.constructor?.name || 'Anonymous');
    current = Object.getPrototypeOf(current);
  }
  
  return chain;
}

function Animal(name) { this.name = name; }
function Dog(name, breed) { 
  Animal.call(this, name); 
  this.breed = breed; 
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

const myDog = new Dog('๋ฐ”๋‘‘์ด', '์ง„๋—๊ฐœ');
console.log(walkPrototypeChain(myDog)); 
// ['Dog', 'Animal', 'Object']

์‹ค์ „ ํ”„๋กœํ† ํƒ€์ž… ์ƒ์† ํ™œ์šฉ ์˜ˆ์ œ

ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ ๊ตฌํ˜„

// ๊ธฐ๋ณธ ํ”Œ๋Ÿฌ๊ทธ์ธ ํด๋ž˜์Šค
function Plugin(name) {
  this.name = name;
  this.enabled = false;
}

Plugin.prototype.enable = function() {
  this.enabled = true;
  console.log(`${this.name} ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ํ™œ์„ฑํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`);
};

Plugin.prototype.disable = function() {
  this.enabled = false;
  console.log(`${this.name} ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ๋น„ํ™œ์„ฑํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`);
};

// ํŠนํ™”๋œ ํ”Œ๋Ÿฌ๊ทธ์ธ๋“ค
function AuthPlugin() {
  Plugin.call(this, 'Authentication');
}
AuthPlugin.prototype = Object.create(Plugin.prototype);
AuthPlugin.prototype.constructor = AuthPlugin;

AuthPlugin.prototype.authenticate = function(user) {
  if (!this.enabled) {
    throw new Error('์ธ์ฆ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.');
  }
  console.log(`${user} ์‚ฌ์šฉ์ž๋ฅผ ์ธ์ฆํ•ฉ๋‹ˆ๋‹ค.`);
};

function LoggingPlugin() {
  Plugin.call(this, 'Logging');
}
LoggingPlugin.prototype = Object.create(Plugin.prototype);
LoggingPlugin.prototype.constructor = LoggingPlugin;

LoggingPlugin.prototype.log = function(message) {
  if (!this.enabled) return;
  console.log(`[LOG] ${message}`);
};

// ์‚ฌ์šฉ ์˜ˆ์ œ
const authPlugin = new AuthPlugin();
const loggingPlugin = new LoggingPlugin();

authPlugin.enable();
loggingPlugin.enable();

authPlugin.authenticate('๊น€์ฒ ์ˆ˜');
loggingPlugin.log('์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ–ˆ์Šต๋‹ˆ๋‹ค.');

๋ฏน์Šค์ธ ํŒจํ„ด ๊ตฌํ˜„

// ๋ฏน์Šค์ธ ๊ฐ์ฒด๋“ค
const Flyable = {
  fly() {
    console.log(`${this.name}์ด(๊ฐ€) ๋‚ ์•„๊ฐ‘๋‹ˆ๋‹ค.`);
  }
};

const Swimmable = {
  swim() {
    console.log(`${this.name}์ด(๊ฐ€) ์ˆ˜์˜ํ•ฉ๋‹ˆ๋‹ค.`);
  }
};

// ๋ฏน์Šค์ธ์„ ์ ์šฉํ•˜๋Š” ํ—ฌํผ ํ•จ์ˆ˜
function mixin(target, ...sources) {
  sources.forEach(source => {
    Object.getOwnPropertyNames(source).forEach(name => {
      if (name !== 'constructor') {
        target.prototype[name] = source[name];
      }
    });
  });
  return target;
}

// ๊ธฐ๋ณธ ๋™๋ฌผ ํด๋ž˜์Šค
function Animal(name) {
  this.name = name;
}

// ์˜ค๋ฆฌ ํด๋ž˜์Šค (๋‚  ์ˆ˜๋„ ์žˆ๊ณ  ์ˆ˜์˜๋„ ํ•  ์ˆ˜ ์žˆ์Œ)
function Duck(name) {
  Animal.call(this, name);
}
Duck.prototype = Object.create(Animal.prototype);
Duck.prototype.constructor = Duck;

// ๋ฏน์Šค์ธ ์ ์šฉ
mixin(Duck, Flyable, Swimmable);

const donald = new Duck('๋„๋„๋“œ');
donald.fly(); // "๋„๋„๋“œ์ด(๊ฐ€) ๋‚ ์•„๊ฐ‘๋‹ˆ๋‹ค."
donald.swim(); // "๋„๋„๋“œ์ด(๊ฐ€) ์ˆ˜์˜ํ•ฉ๋‹ˆ๋‹ค."

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด ๊ตฌํ˜„

// ๊ธฐ๋ณธ ์ปคํ”ผ ํด๋ž˜์Šค
function Coffee() {
  this.cost = 1000;
  this.description = '๊ธฐ๋ณธ ์ปคํ”ผ';
}

Coffee.prototype.getCost = function() {
  return this.cost;
};

Coffee.prototype.getDescription = function() {
  return this.description;
};

// ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋ณธ ํด๋ž˜์Šค
function CoffeeDecorator(coffee) {
  this.coffee = coffee;
}

CoffeeDecorator.prototype.getCost = function() {
  return this.coffee.getCost();
};

CoffeeDecorator.prototype.getDescription = function() {
  return this.coffee.getDescription();
};

// ๊ตฌ์ฒด์ ์ธ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋“ค
function MilkDecorator(coffee) {
  CoffeeDecorator.call(this, coffee);
}
MilkDecorator.prototype = Object.create(CoffeeDecorator.prototype);
MilkDecorator.prototype.constructor = MilkDecorator;

MilkDecorator.prototype.getCost = function() {
  return this.coffee.getCost() + 500;
};

MilkDecorator.prototype.getDescription = function() {
  return this.coffee.getDescription() + ', ์šฐ์œ ';
};

function SugarDecorator(coffee) {
  CoffeeDecorator.call(this, coffee);
}
SugarDecorator.prototype = Object.create(CoffeeDecorator.prototype);
SugarDecorator.prototype.constructor = SugarDecorator;

SugarDecorator.prototype.getCost = function() {
  return this.coffee.getCost() + 200;
};

SugarDecorator.prototype.getDescription = function() {
  return this.coffee.getDescription() + ', ์„คํƒ•';
};

// ์‚ฌ์šฉ ์˜ˆ์ œ
let myCoffee = new Coffee();
myCoffee = new MilkDecorator(myCoffee);
myCoffee = new SugarDecorator(myCoffee);

console.log(myCoffee.getDescription()); // "๊ธฐ๋ณธ ์ปคํ”ผ, ์šฐ์œ , ์„คํƒ•"
console.log(myCoffee.getCost()); // 1700

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹ ๋งˆ์Šคํ„ฐํ•˜๊ธฐ

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

ํ•ต์‹ฌ ํฌ์ธํŠธ๋ฅผ ์ •๋ฆฌํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ƒ์†: ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ํด๋ž˜์Šค ๊ธฐ๋ฐ˜์ด ์•„๋‹Œ ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ƒ์†์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ: ํ”„๋กœํ† ํƒ€์ž…์„ ํ™œ์šฉํ•˜๋ฉด ๋ฉ”์„œ๋“œ๋ฅผ ๊ณต์œ ํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ์–ด์š”.
  3. ๋™์  ํŠน์„ฑ: ์‹คํ–‰ ์‹œ๊ฐ„์— ํ”„๋กœํ† ํƒ€์ž…์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์–ด ๋งค์šฐ ์œ ์—ฐํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  4. ์ฒด์ธ ํƒ์ƒ‰: ํ”„๋กœํผํ‹ฐ ๊ฒ€์ƒ‰ ์‹œ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์„ ๋”ฐ๋ผ ์˜ฌ๋ผ๊ฐ€๋ฉฐ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ดํ•ดํ•ด์•ผ ํ•ด์š”.
  5. ์•ˆ์ „ํ•œ ์‚ฌ์šฉ: Object.getPrototypeOf, Object.setPrototypeOf, Object.create ๋“ฑ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์•ˆ์ „ํ•˜๊ฒŒ ํ”„๋กœํ† ํƒ€์ž…์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์„ ๋งˆ์Šคํ„ฐํ•˜๋ฉด ES6 ํด๋ž˜์Šค ๋ฌธ๋ฒ•๋„ ๋” ๊นŠ์ด ์žˆ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ณ , ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋‚ด๋ถ€ ๋™์ž‘ ์›๋ฆฌ๋„ ํŒŒ์•…ํ•˜๊ธฐ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค. ์‹ค๋ฌด์—์„œ ๋งˆ์ฃผ์น˜๋Š” ๋ณต์žกํ•œ ์ƒ์† ๊ตฌ์กฐ๋‚˜ ๋””์ž์ธ ํŒจํ„ด๋„ ์ž์‹  ์žˆ๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”.

์ง€๊ธˆ๋ถ€ํ„ฐ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์—์„œ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹์„ ์ ๊ทน ํ™œ์šฉํ•ด๋ณด์„ธ์š”. ๋” ๊น”๋”ํ•˜๊ณ  ํšจ์œจ์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค!

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ด๋‹ ์™„๋ฒฝ ๊ฐ€์ด๋“œ | devdong