๐ŸฆŽ [๋”ฅ๋‹ค์ด๋ธŒ ์Šคํ„ฐ๋””] 19. ํ”„๋กœํ† ํƒ€์ž…

1. ํ”„๋กœํ† ํƒ€์ž…?

js ๋Š” ํ”„๋กœํ†  ํƒ€์ž… ๊ธฐ๋ฐ˜์˜ ๊ฐ์ฒด์ง€ํ–ฅ ๋ ฅํ•œ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋‹ค.

2. ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ?

Object๋Š” ํฌ๊ฒŒ ์–ด๋–ค ์ƒํƒœ๋ฅผ ๊ฐ€์ง€๋Š” field (property)์™€ ํ•จ์ˆ˜์ธ method ๋ฅผ ๊ฐ€์ง„๋‹ค. Class ๋Š” ์ด๋Ÿฐ Object ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” 'ํ‹€'์˜ ๊ฐœ๋…์ด๋‹ค. class ์˜ instance ๋ฅผ object ๋ผ๊ณ  ํ•œ๋‹ค.

2-1. SOLID ์›์น™

  1. ๋‹จ์ผ ์ฑ…์ž„ ์›์น™ (Single Responsiblity Principle)
    ๋ชจ๋“  ํด๋ž˜์Šค๋Š” ๊ฐ๊ฐ ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค. ํด๋ž˜์Šค๋Š” ๊ทธ ์ฑ…์ž„์„ ์™„์ „ํžˆ ์บก์Šํ™”ํ•ด์•ผ ํ•จ์„ ๋งํ•œ๋‹ค.

  2. ๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™ (Open Closed Principle)
    ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ๊ณ  ์ˆ˜์ •์—๋Š” ๋‹ซํ˜€์žˆ๋Š”. ๊ธฐ์กด์˜ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์œผ๋ฉด์„œ( Closed), ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋„๋ก(Open) ์„ค๊ณ„๊ฐ€ ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ์›์น™์„ ๋งํ•œ๋‹ค.

  3. ๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™ (Liskov Substitution Principle)
    ์ž์‹ ํด๋ž˜์Šค๋Š” ์–ธ์ œ๋‚˜ ์ž์‹ ์˜ ๋ถ€๋ชจ ํด๋ž˜์Šค๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์›์น™์ด๋‹ค. ์ฆ‰ ๋ถ€๋ชจ ํด๋ž˜์Šค๊ฐ€ ๋“ค์–ด๊ฐˆ ์ž๋ฆฌ์— ์ž์‹ ํด๋ž˜์Šค๋ฅผ ๋„ฃ์–ด๋„ ๊ณ„ํš๋Œ€๋กœ ์ž˜ ์ž‘๋™ํ•ด์•ผ ํ•œ๋‹ค. ์ž์‹ํด๋ž˜์Šค๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ์ฑ…์ž„์„ ๋ฌด์‹œํ•˜๊ฑฐ๋‚˜ ์žฌ์ •์˜ํ•˜์ง€ ์•Š๊ณ  ํ™•์žฅ๋งŒ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•ด์•ผ LSP๋ฅผ ๋งŒ์กฑํ•œ๋‹ค.

  4. ์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ ์›์น™ (Interface Segregation Principle)
    ํ•œ ํด๋ž˜์Šค๋Š” ์ž์‹ ์ด ์‚ฌ์šฉํ•˜์ง€์•Š๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๊ตฌํ˜„ํ•˜์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค. ํ•˜๋‚˜์˜ ์ผ๋ฐ˜์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋ณด๋‹ค ์—ฌ๋Ÿฌ๊ฐœ์˜ ๊ตฌ์ฒด์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋‚ซ๋‹ค.

  5. ์˜์กด ์—ญ์ „ ์›์น™ (Dependency Inversion Principle)
    ์˜์กด ๊ด€๊ณ„๋ฅผ ๋งบ์„ ๋•Œ ๋ณ€ํ™”ํ•˜๊ธฐ ์‰ฌ์šด ๊ฒƒ ๋˜๋Š” ์ž์ฃผ ๋ณ€ํ™”ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค๋Š” ๋ณ€ํ™”ํ•˜๊ธฐ ์–ด๋ ค์šด ๊ฒƒ, ๊ฑฐ์˜ ๋ณ€ํ™”๊ฐ€ ์—†๋Š” ๊ฒƒ์— ์˜์กดํ•˜๋ผ๋Š” ๊ฒƒ์ด๋‹ค. ํ•œ๋งˆ๋””๋กœ ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค๋ณด๋‹ค ์ธํ„ฐํŽ˜์ด์Šค๋‚˜ ์ถ”์ƒ ํด๋ž˜์Šค์™€ ๊ด€๊ณ„๋ฅผ ๋งบ์œผ๋ผ๋Š” ๊ฒƒ์ด๋‹ค.

2-2.์ ˆ์ฐจ์ง€ํ–ฅ vs ๊ฐ์ฒด์ง€ํ–ฅ

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

2-3.์ƒ์†๊ณผ ํ”„๋กœํ† ํƒ€์ž…

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

const person = { name: 'Lee' };

//persone ๊ฐ์ฒด๋Š” __proto__ ํ”„๋กœํผํ‹ฐ๋ฅผ ์†Œ์œ ํ•˜์ง€ ์•Š๋Š”๋‹ค.
console.log(person.hasOwnProperty('__proto__') //false

//๋ชจ๋“  ๊ฐ์ฒด๋Š” Object.prototype์˜ ์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ __proto__๋ฅผ ์ƒ์†๋ฐ›์•„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
console.log({}.__proto__ === Object.prototype); //true

===========================< ๋ฌธ์ œ >=============================

1. __proto__ ์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ํ”„๋กœํ† ํƒ€์ž…์— ์ ‘๊ทผํ•ด์•ผํ•˜๋Š” ์ด์œ ๋Š”?

ํ”„๋กœํ† ํƒ€์ž…์„ ๊ฐ€๋ฆฌํ‚ค๋Š” [[Prototype]] ๋‚ด๋ถ€ ์Šฌ๋กฏ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ์•„๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์›์น™์ ์œผ๋กœ ๋‚ด๋ถ€ ์Šฌ๋กฏ๊ณผ ๋‚ด๋ถ€ ๋ฉ”์„œ๋“œ์— ์ง์ ‘ ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋‹จ, ๊ฐ„์ ‘์ ์œผ๋กœ ๋‚ด๋ถ€ ์Šฌ๋กฏ์˜ ๊ฐ’, ์ฆ‰ ํ”„๋กœํ†  ํƒ€์ž…์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ์ƒํ˜ธ ์ฐธ์กฐ์— ์˜ํ•ด ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์ด ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋‹ค. ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์€ ๋‹จ๋ฐฉํ–ฅ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋กœ ๊ตฌํ˜„๋˜์–ด์•ผํ•œ๋‹ค. ์ฆ‰, ํ”„๋กœํผํ‹ฐ ๊ฒ€์ƒ‰ ๋ฐฉํ–ฅ์ด ํ•œ์ชฝ ๋ฐฉํ–ฅ์œผ๋กœ๋งŒ ํ˜๋Ÿฌ๊ฐ€์•ผํ•œ๋‹ค. ์•„๋ฌด๋Ÿฐ ์ฒดํฌ์—†์ด ๋ฌด์กฐ๊ฑด์ ์œผ๋กœ ํ”„๋กœํ† ํƒ€์ž…์„ ๊ต์ฒดํ•  ์ˆ˜ ์—†๋„๋ก, proto ์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ํ”„๋กœํ† ํƒ€์ž…์— ์ ‘๊ทผํ•˜๊ณ  ๊ต์ฒดํ•˜๋„๋ก ๊ตฌํ˜„๋˜์–ด์žˆ๋‹ค.

์ ‘๊ทผ์ž ํ”„๋กœํผํ‹ฐ๋Š” ์ž์ฒด์ ์œผ๋กœ ๊ฐ’[[value]] ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–์ง€ ์•Š๊ณ , ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์„ ์ฝ๊ฑฐ๋‚˜ ์ €์žฅํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์ ‘๊ทผ์ž ํ•จ์ˆ˜, ์ฆ‰ get,set ํ”„๋กœํผํ‹ฐ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋กœ ๊ตฌ์„ฑ๋œ ํ”„๋กœํผํ‹ฐ์ด๋‹ค.

2. ์•„๋ž˜ ์ฝ”๋“œ์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋งํ•˜๊ณ  ์™œ ๊ทธ๋Ÿฐ์ง€ ์ด์œ ๋ฅผ ์„ค๋ช…ํ•ด๋ณด์‹œ์˜ค.

const Person = (function() {
  function Person(name){
    this.name = name;
  }
  
  Person.prototype = {
    sayHello() {
      console.log(`Hi! My name is ${this.name}`);
    }
  }
  return Person;
}());

const me = new Person('Lee');

me.sayHello = function() {
  console.log(`Hey! My name is ${this.name}`);
}
//์ด ๊ณผ์ •์—์„œ ํ”„๋กœํ† ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ธ์Šคํ„ด์Šค ํ”„๋กœํผํ‹ฐ๋กœ ๋ฎ์–ด์”Œ๋Š”๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์ธ์Šคํ„ด์Šค ํ”„๋กœํผํ‹ฐ๋กœ ์ถ”๊ฐ€๋œ๋‹ค. 
//์˜ค๋ฒ„๋ผ์ด๋”ฉ.(์ƒ์†๊ด€๊ณ„์— ์˜ํ•ด ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ€๋ ค์ง€๋Š” ํ˜„์ƒ์„ ํ”„๋กœํผํ‹ฐ ์„€๋„์ž‰ ์ด๋ผ๊ณ  ํ•œ๋‹ค.  
//ํ”„๋กœํ† ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๋ฅผ ํ•˜์œ„ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ๋ณ€๊ฒฝ, ๋˜๋Š” ์‚ญ์ œํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. 
//get ์•ก์„ธ์Šค๋Š” ํ—ˆ์šฉ๋˜๋‚˜, set ์•ก์„ธ์Šค๋Š” ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค. ํ”„๋กœํ† ํƒ€์ž…์— ์ง์ ‘ ์ ‘๊ทผํ•ด์•ผํ•œ๋‹ค.

me.sayHello();  //Q1.์ถœ๋ ฅ๊ฐ’์€?
'Hey! My name is Lee'

//์ธ์Šคํ„ด์Šค ๋ฉ”์„ธ์ง€๋ฅผ ์‚ญ์ œํ•œ๋‹ค. 
delete me.sayHello;
//ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. 
me.sayHello(); //Q2.์ถœ๋ ฅ๊ฐ’์€?
'Hi! My name is Lee'

//ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ๊ฐ€ ์‚ญ์ œ๋œ๋‹ค. 
delete me.sayHello;
me.sayHello(); //Q3.์ถœ๋ ฅ๊ฐ’์€?
//type err => 

//delete Person.prototype.sayHello -> ์ด๋ ‡๊ฒŒ ํ•ด์•ผ ์ง€์›Œ์ง! 
//me.prototype ์€ ์ธ์Šคํ„ด์Šค์—์„œ ์ ‘๊ทผ ์•ˆ๋จ! 

//Q4.์ด์œ ๋Š”?

์ง€์˜

3. ๊ฒฐ๊ณผ๊ฐ’์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๊ทธ๋ฆฌ๊ณ  ์™œ?

function Circle(radius) {
  this.radius = radius;
}

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


4. ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ sayHello๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝํ•˜๊ณ ,์‚ญ์ œํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

const Person = (function() {
  function Person(name){
    this.name = name;
  }
  
  //์ƒ์„ฑ์ž ํ•จ์ˆ˜์˜ prototype ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ํ”„๋กœํ† ํƒ€์ž…์„ ๊ต์ฒด
  //prototype์— ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์„ ํ• ๋‹นํ–ˆ๋‹ค. ์ด๋Š” ํ”„๋กœํ† ํƒ€์ž…์„ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด๋กœ ๊ต์ฒดํ•œ ๊ฒƒ์ด๋‹ค.
  Person.prototype = {
    sayHello() {
      console.log(`Hi! My name is ${this.name}`);
    }
  }
  return Person;
}());

const me = new Person('Lee');

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ