- ์ด ํฌ์คํธ๋ ์นด์ผ์ฌ์จ์ YOU DON'T KNOW JS, ์ ์ง์ฑ๋์ ํ์ ์คํฌ๋ฆฝํธ ํต์คํํธ๋ฅผ ์ฐธ๊ณ ํ์ฌ ์ดํดํ ๋ฐํ์ผ๋ก ์ ์ ๋ ธํธ์ ๋๋ค. ๋ฐ์ ํ๋ ๊ฐ๋ฐ์๊ฐ ๋ ์ ์๋๋ก ์ค๋ช ์ด ์๋ชป ๋์๋ค๊ฑฐ๋ ์กฐ๊ธ ๋ ๋ณด์ถฉ์ค๋ช ์ด ํ์ ํ์๋ค๊ณ ์๊ฐ๋์๋ฉด ๋๊ธ ๋จ๊ฒจ ์ฃผ์ธ์. ์ธ์ ๋ ์ง ํ์์ ๋๋ค ๐
์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ๋งํ๋ ์์ (ES6,ES5)
์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ฐ๋ฉด ์ธ์๋ก ์ ๊ทธ๋ ์ง ? ๋ผ๊ณ ์๊ฐํ๋ ๋ถ๋ถ์ ๋ต์๋ prototype์ด ์๋ฆฌ๋ฅผ ์งํค๊ณ ์ ์์๋ค. ์ด ๊ธ์์ ๊ทธ๋ฐ ๋ถ๋ถ์ ๋ ์ค์ค๋ก๋ฟ๋ง ์๋๋ผ ์ฝ๋ ๋ถ๋ค์๊ฒ๋ ๋์์ด ๋์์ผ๋ฉด ํ๋ค.
์ผ๋จ OOP ์์ ๊ด๊ณ์ ๋ํ theme์ ๋งํ์๋ฉด, ์์์ ์์/๋ถ๋ชจ ํด๋์ค์ ์ํด ์๋ ๋ฉ์๋์ ์์ฑ ๋ค์ ๋ฌผ๋ ค ๋ฐ๋ ์๋ก์ด child ํด๋์ค๋ฅผ ๋ง๋ค์๊ฐ ์๋ค. ์ฌ๊ธฐ์ ๋งํ๋ ๋ถ๋ชจ ํด๋์ค๋ superclass/base class๋ก ๋ถ๋ ค์ง๊ธฐ๋ ํ๊ณ childํด๋์ค๋ subclasses/derived classes๋ก ๋ถ๋ ค์ง๊ธฐ๋ ํ๋ค. ์์๊ด๊ณ๋ ํด๋์ค๊ฐ์ 'kind-of' or 'is-a' ๊ด๊ณ๋ก ๋ํ๋ผ ์ ์๋ค. ์๋ฅผ ๋ค์ด "a dog is an animal" or "a dog is a kind of animal". ๊ฐ๋ ๋๋ฌผ์ด๋ค, ๊ฐ๋ ๋๋ฌผ์ ํ ์ข ๋ฅ์ด๋ค. ๋ผ๋ ๊ด๊ณ๊ฐ ์ฑ๋ฆฝํ๋ค. 'HAS-A' ๋ผ๋ ํฌํจ๊ด๊ณ๋ ์๋๋ฐ ํ ํด๋์ค์์ ๋ค๋ฅธ ํด๋์ค๋ฅผ ๋ฉค๋ฒ๋ณ์๋ก ์ ์ธํ๋ ๊ฒ์ด๋ค. oop ๊ธฐ์ ์ธ ์์์ ์์ํด๋์ค๊ฐ ๋ถ๋ชจํด๋์ค์์ ํ์๋๊ณ ๋ถ๋ชจ์ ๋ชจ๋ ์์ฑ๊ณผ ๋ฉ์๋๋ฅผ ์ด์ด๋ฐ๋๋ค. ์ด๋ ๊ฒ ์ด์ด๋ฐ์ ์์ฑ๊ณผ ๋ฉ์๋๋ ์์ํด๋์ค์์ ๋ค์ ์ฌ์ ์ ํ ํ์๊ฐ ์๋ค. ํ์ง๋ง ํ์์ ๋ฐ๋ผ ์์ํด๋์ค์์ ๋ฉ์๋๋ ์์ฑ์ ์ถ๊ฐํ๊ธฐ๋ ํ๊ณ , ์์๋ ๋ฉ์๋์ ๋ด๋ถ ๋ก์ง์ ๋ณ๊ฒฝํ ์๋ ์๋ค. ES06 ์๋ฐ์คํฌ๋ฆฝํธ์์๋ class, extends๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฐ ์์์ ์ธ ๊ฐ๋ ์ ํํํ ์ ์๋ค.
1 . IS-A
class Bicycle {
constructor() {
this.numberOfWheel = 4 //<-privateํ๊ฒ ํ๊ณ ์ฐจ์ผ๋๊ฐ ๊ฐ์ง๊ณ ์ฌ ์ ์๋?
}
}
class MountainBike extends Bicycle {
constructor() {
super(numberOfWheel)
}
getNumOfWheel() {
return this.numOfWheel
}
}
2 . HAS-A
- ํฉ์ฑ๊ด๊ณ (composition)-๊ฐํ๊ด๊ณ
engine ๊ฐ์ฒด๋ ์ธ์คํด์คํ ๋ ๋ ์์ฑ๋๊ณ myCarr๊ฐ null์ด ๋๋ฉด engine ๊ฐ์ฒด๋ ์ ๊ฑฐ๋๋ค.
class Engine {}
class Car {
#engine
constructor() {
this.#engine = new Engine()
}
}
let myCar = new Car()
myCar = null
- ์งํฉ๊ด๊ณ (aggregation)- ์ฝํ๊ด๊ณ car๊ฐ์ฒด๊ฐ ์์ฑ๋ ๋ ์ธ๋ถ์์ engine ๊ฐ์ฒด๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌํ๋ค. car ๊ฐ์ฒด๊ฐ null ์ด ๋๋๋ผ๋ engine ๊ฐ์ฒด๋ ์ฌ๋ผ์ง์ง ์๋๋ค.
class Engine {}
class car {
#engine
constructor(engine) {
this.engine = engine
}
}
let engine = new Engine()
let car = new Car(engine)
ES06 ์์ ๊ตฌํ ํ๊ธฐ
ES06 ํด๋์ค์์ super์ this ํค์๋๋ฅผ ์ด์ฉํด ๋ถ๋ชจํด๋์ค์ ์ ์ธ๋ ๋ฉค๋ฒ ๋ฉ์๋๋ ๋ฉค๋ฒ ๋ณ์์ ์ ๊ทผํ ์ ์์ต๋๋ค.
- super - ๋ถ๋ชจํด๋์ค์ public ๋ฉค๋ฒ๋ง ์ ๊ทผ ๊ฐ๋ฅ.
- this - ์์๋ฐ์ ๋ฉค๋ฒ์ ํ์ฌํด๋์ค๋ด์ ๋ชจ๋ ๋ฉค๋ฒ ์ ๊ทผ๊ฐ๋ฅ.
class PC {
#ram
constructor(hddCapacity) {
this.hddCapacity = hddCapacity
this.#ram = '0GB'
}
set ramCapacity(value) {
this.#ram = value
}
get ramCapacity() {
return this.#ram
}
getHddCapacity() {
return this.hddCapacity
}
}
class Desktop extends PC {
ํผ
constructor(hddCapacity) {
super(hddCapacity)
}
getInfo() {
console.log(
`1. HDD capacity : ${super.getHddCapacity()},${super.hddCapacity}`,
)
console.log(
`2. HDD capacity : ${this.getHddCapacity()},${this.hddCapacity}`,
)
this.hddCapacity = '2000G'
console.log(
`3. HDD capacity : ${super.getHddCapacity()},${super.hddCapacity}`,
)
console.log(
`4. HDD capacity : ${this.getHddCapacity()},${this.hddCapacity}`,
)
super.ramCapacity = '16G'
console.log(`5. RAM capacity : ${this.ramCapacity},${super.ramCapacity}`)
this.ramCapacity = '8G'
console.log(`6. RAM capacity : ${this.ramCapacity},${super.ramCapacity}`)
}
}
let mydesktop = new Desktop('500G')
mydesktop.getInfo()
// 1. HDD capacity : 500G,undefined
// 2. HDD capacity : 500G,500G
// 3. HDD capacity : 2000G,undefined
// 4. HDD capacity : 2000G,2000G
// 5. RAM capacity : 16G,16G
// 6. RAM capacity : 8G,8G
ํ์ฅ๋ ํด๋์ค(Desktop)์์ ์์ ํด๋์ค์ ๋ฉค๋ฒ๋ณ์์ ์ ๊ทผํ๊ธฐ ์ํด์ , ๋ถ๋ชจ ํด๋์ค ์์ฑ์๋ฅผ ํธ์ถํด์ค์ผํ๋ค. ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ๋ถ๋ชจํด๋์ค์ ๋ฉค๋ฒ ๋ณ์๋ฅผ ํ์ฅ๋ ํด๋์ค์ constructor ์ ๋งค๊ฐ๋ณ์๋ก ๋๊ฒจ์ฃผ๊ณ super()์๋ constructor ์ ๋งค๊ฐ๋ณ์๋ฅผ ๊ฐ์ด ๋๊ฒจ์ค๋ค.(super() = ๋ถ๋ชจํด๋์ค์ ์์ฑ์๋ฅผ ํธ์ถํ๋ ํจ์)
constructor(hddCapacity)
{
super(hddCapacity)
}
1,3 ๋ฒ์์ superํค์๋๋ก ๋ถ๋ชจ์ public ๋ฉค๋ฒ ๋ณ์์ ์ ๊ทผํ๋ฉด undefined๋ฅผ returnํ๋ค. public ๋ฉค๋ฒ ๋ณ์์ผ์ง๋ผ๋, superํค์๋๋ก๋ ์์ํด๋์ค์ ๋ฉค๋ฒ๋ณ์๋ฅผ ์ง์ ํธ์ถํด ๊ฐ์ ธ์ฌ ์ ์๋ค. ํ์ง๋ง this ๋ ์ง์ ํธ์ถ ๊ฐ๋ฅ ํ๋ค. ์์ํด๋์ค์ private ๋ฉค๋ฒ๋ณ์์ ์ ๊ทผ๊ณผ ์์ ์ getter ์ setter๋ก ๊ฐ๋ฅํ๋ค.
์ ๋ฆฌ
super | this | |
---|---|---|
parent pubic ๋ฉค๋ฒ ๋ณ์ ์ง์ ์ ๊ทผ | โ (getter/๋ฉค๋ฒ ๋ฉ์๋๋ก ์ ๊ทผ) | โ |
parent pubic ๋ฉค๋ฒ ํจ์ ์ง์ ์ ๊ทผ | โ | โ |
parent private ๋ฉค๋ฒ ๋ณ์ ์ง์ ์ ๊ทผ | โ ( ๋ถ๋ชจ ํด๋์ค์ setter์์ผ๋ฉด ๊ฐ๋ฅ) | โ ( ๋ถ๋ชจ ํด๋์ค์ setter์์ผ๋ฉด ๊ฐ๋ฅ) |
Class ๋ค์ [ [ prototype ] ] ์ฒด๊ณ
์์์ ์์ ๊ฐ๋
์ ์ค๋ช
ํ๊ธฐ ์ํด ์๋ฐ์คํฌ๋ฆฝํธ์ class๋ฅผ ์ด์ฉํ์๋ค. ์ฌ๊ธฐ์
์ฌ์ฉ๋ class๋ผ๋ ํค์๋๋ ์ฌ์ค [[prototype]]
์ฒด๊ณ์ ๊ธฐ๋ฐ์ ๋๊ณ ์๋ค. You Don't
know Js ์ ์ ์์ธ ์นด์ผ ์ฌ์จ์ ์๋ฐ์คํฌ๋ฆฝํธ์ ์ฒด๊ณ๋ฅผ ๋ง์ ๊ฐ๋ฐ์๋ค์ด ํด๋์ค
๋์์ธ ํจํด์ผ๋ก ์คํํ๋ ค๋ ์๊ตฌ๋ฅผ ์ถฉ์กฑํ๊ธฐ ์ํด Syntatic sugar๋ฅผ ์จ๊ฐ๋ฉฐ
์๋ฐ์คํฌ๋ฆฝํธ์ ์ฒด๊ณ๋ฅผ ์ต์ง๋ก ๊ณ ์น๊ฒ์ ๋ถ๊ณผํ๋ค๊ณ ๋งํ๋ค. ๊ทธ ์ด์ ์ค ํ๋๊ฐ ์๋ง
์ด๋ฐ ๋
ผ๋ฆฌ๋ก ๋ท๋ฐ์นจ ๋ ์ ์์ ๊ฒ ๊ฐ๋ค. ํด๋์ค์งํฅ ์ธ์ด์์ ํด๋์ค์
์ธ์คํด์คํ๋ ํด๋์ค์ ๋ด๋ถ๋ฅผ ์ธ์คํด์ค๋ก ๋ณต์ฌํ๋ค. ์ด๋ฐ๊ณผ์ ์ ๋งค ์ธ์คํด์ค๋ง๋ค
์ผ์ด๋๋ค. ํ์ง๋ง ์๋ฐ์คํฌ๋ฆฝํธ๋ ์ด๋ฐ ๋ณต์ฌ๊ณผ์ ์ด ์๊ณ , [[prototype]]
๋งํฌ๋ก
๊ฐ์ฒด๋ค์ ์ฐ๊ฒฐํ๋ค. ๊ทธ๋ฌ๋๊น ํด๋์ค ์งํฅ ์ธ์ด์์์ ์์์ ๊ฐ๋
๊ณผ ์คํฌ๋ฆฝํธ ์ธ์ด์
๋์ ํน์ฑ๊ณผ ํผํฉ๋์๋ค๋ผ๊ณ ๋ณผ ์ ์์ผ๋ฉฐ ์์(inherit)๋ณด๋ค๋ ์์(delegation)์ด๋
๋ง์ด ๋ ๊ฐ๊น๋ค.
์์์ ์ค๋ช ํ ๋ด์ฉ์ ๋ฏธ๋ฃจ์ด๋ณผ ๋, ์๋ฐ์คํฌ๋ฆฝํธ์์ ํ๋กํ ํ์ ๋งํฌ๋ก ๊ฐ์ฒด๋ฅผ ์ฐ๊ฒฐํ๋ค๊ณ ํ๊ณ class๋ ํค์๋๋ ์ ํต์ ํด๋์ค์งํฅ ์ธ์ด์๋ ๋ค๋ฅด๊ฒ ์๋ํ๋คํ์ผ๋, ์ด ๋ง์ ํฉ์น๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋งํ๋ ํด๋์ค๋ ํ๋กํ ํ์ ๋งํฌ๋ก ๊ฐ์ฒด๋ฅผ ์ฐ๊ฒฐํ๋ ๋ฐฉ์์ผ๋ก ์ดํด ํ ์ ์๋ค. ๊ทธ๋ผ ์ฌ๊ธฐ์ ๋๋ ์๋ฌธ์ ์ new ํค์๋๋ก ๊ฐ์ฒด(์ธ์คํด์ค)๋ฅผ ์์ฑํ๋ ๊ฒ์ ์๋ฐ์คํฌ๋ฆฝํธ๋ ํด๋์ค์งํฅ ์ธ์ด์์๋ ๋๊ฐ์ด ์ฌ์ฉํ๋๋ฐ ์ด๋ป๊ฒ ๋ด๋ถ ๋์์๋ฆฌ๊ฐ ๋ค๋ฅธ๊ฐ์ด๋ค.
function Foo(name) {
this.name = name
console.log(this) // Foo()-> global / new Foo() -> Foo {name:'kelly'}
}
/*===============================*/
//new ๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด, ๊ทธ๋ฅ ํจ์ํธ์ถ
let b = Foo('kelly')
console.log(b) //undefined
console.log(b.name) //undefined
/*===============================*/
//new ์ฌ์ฉํ๋ฉด ์์ฑ์ ํธ์ถ
let a = new Foo('kelly')
console.log(a.name) //kelly
console.log(a.__proto__) //Foo {}
console.log(a.prototype) //undefined <-- โผ๏ธ ์ผ๋ฐ ๊ฐ์ฒด์๋ ์์ฑ๋์ง ์๋๋ค
new ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ํจ์๋ฅผ ํธ์ถํ ๊ฒ๊ณผ ์๋๊ฒ์ ๋น๊ตํ๊ฒ์ด๋ค. new ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ๊น์ง
Foo( ) ๋ ์ผ๋ฐํจ์์ด๋ค. ๊ทธ๋์ this ๋ํ ๊ธ๋ก๋ฒ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์๋ค. ํ์ง๋ง new
Foo( ) ๋ก ํธ์ถํ๊ฒ ๋๋ฉด Foo() ์์ฑ์ ํจ์๊ฐ ๋๋ค. ์ฆ, new ํค์๋๋ก Foo()๋ฅผ ํธ์ถํ๋ฉด,
์๋ก์ด ๋น ๊ฐ์ฒด๊ฐ ๋ง๋ค์ด์ง๊ณ ์ด ๊ฐ์ฒด(a)๋ [[prototype]]
๋ผ๋ ๋ด๋ถ ํ๋กํผํฐ๊ฐ ์๊ธฐ๊ณ ,[[prototype]]
๋ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ๋ ํผ๋ฐ์ค๋ก ์ฌ์ฉ๋๋ค. ์ด๋ ๊ฒ ์์ฑ๋ ๊ฐ์ฒด๋ ํด๋น ํจ์ this๋ก
๋ฐ์ธ๋ฉ์ด ๋๋ค. ์์์ ์ธ๊ธ๋ [[prototype]]
๋ผ๋ ๋ด๋ถ ํ๋กํผํฐ๋ ์๋ฐ์คํฌ๋ฆฝํธ์์
๋ชจ๋ ๊ฐ์ฒด๋ [[prototype]]
์ด๋ผ๋ ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๋ค (Chrome/vsCode/WebStorm etc
์์๋ proto ). ๋ฐ์ ์ด๋ฏธ์ง๋ฅผ ์ฐธ๊ณ ํ๋ฉด [[prototype]]
๊ฐ ์์ฑ๋์๋ค.
ย
[[prototype]]
์ด ์ด๋ค ์ญํ ์ ํ๋์ง ์ข ๋ ์์ธํ๊ฒ ์ดํด๋ณด์.
function Foo(name, menu) {
this.name = name
}
let bar = new Foo('kelly')
console.log(bar.hasOwnProperty('name')) //true
console.log(bar.__proto__ === Foo.prototype) // true
console.log(bar.constructor === Foo.prototype.constructor) // true
console.log(Foo.prototype.constructor === Foo)
console.log(bar.constructor === Foo)
์์ฑ๋ ๊ฐ์ฒด(bar)์ name ํ๋กํผํฐ ์ ๋ฌด๋ฅผ ํ์ธํ๋ hasOwnProperty('name' )
๋ true๋ฅผ
๋ฐํํ๋ค. ์ผ๋จ ์ฌ๊ธฐ์ bar ๊ฐ์ฒด์ hasOwnProperty()
๋ฉ์๋๋ฅผ ์ ์ธ ํ ์ ์ด ์์์๋
๋ถ๊ตฌํ๊ณ ์๋ฌ๊ฐ ๋์ง์๊ณ ํจ์๊ฐ ๋์ํ๋ ์ด์ ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ bar๊ฐ์ฒด์ hasOwnProperty()
๋ฉ์๋๊ฐ ์์ผ๋ฉด ์ด ๊ฐ์ฒด์ [[prootype]]
(๋ด๋ถ ๋งํฌ) ์ ์ํด ์ฐ๊ฒฐ ๋์ด์๋ ๊ฐ์ฒด๋ฅผ
๋ฐ๋ผ๊ฐ๋ฉด์ ํ๋กํผํฐ๋ฅผ ์ฐพ์ ๋๊น์ง ์ ๋ฌด๋ฅผ ํ์ธํ๋ค. ์ด๊ฒ ํ๋กํ ํ์
์ฒด์ด๋(Prototype
Chaining)์ด๋ฉฐ ์ผ๋ จ์ ๋งํฌ๋ค์ ํ๋กํ ํ์
์ฐ์(prototype chain)๋ผ๊ณ ํ๋ค. ๊ทธ๋ผ ์ด๋ฐ
์ฐ์์ ๋์ ์ด๋์ผ๊น? hasOwnProperty๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฐ์ฒด Object.prototype
์ด๋ค.
JavaScript์์ ๊ฑฐ์ ๋ชจ๋ ๊ฐ์ฒด๋ Object์ ์ธ์คํด์ค์ด๋ฏ๋ก, Object.prototype ์์ ์์ฑ๊ณผ
๋ฉ์๋๋ฅผ ์์๋ฐ๋๋ค. ๋ค์ด์ด๊ทธ๋จ์ผ๋ก ๋ํ๋ด๋ฉด ์ด๋ฐ ์ฐ์๊ฐ ๋ํ๋๋ค.
๊ฐ์ฒด bar๊ฐ ์์ฑ๋๋ฉด ๋ด๋ถ์ ์ผ๋ก [[prototype]]
ํ๋กํผํฐ๋ Foo()ํจ์์ prototype
ํ๋กํผํฐ๊ฐ
๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๊ฒ ๋๋ค. ์ฐธ๊ณ ๋ก ์๋ฐ์คํฌ๋ฆฝํธ์ ๊ฐ์ฒด ์์ฑ ๊ท์น์ธ ํจ์ ๊ฐ์ฒด๋
length
์ prototype
์ด๋ผ๋ ํ๋กํผํฐ๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ฐ์ง๋ค. ๊ทธ๋ฆฌ๊ณ ํจ์๊ฐ์ฒด ๋ํ
๊ฐ์ฒด์ด๋ฏ๋ก [[prototype]]
ํ๋กํผํฐ๋ ํฌํจํ๋ค.{' '}
์ด๋ฌํ ์์ฑ๊ท์น์ ์ํด Foo.prototype
์ ์ ๊ทผ ํ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ
Foo.prototype
๋ํ ๊ฐ์ฒด์ด๋ฏ๋ก constructor ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
.prototype
๋ ํผ๋ฐ์ค๋ฅผ ๊ฐ์ง ํจ์, ์ฆ ์์ ์์ ์์๋ Foo() ํจ์๋ฅผ
๊ฐ๋ฆฌํจ๋ค.
constructor์ ๋ํด ์กฐ๊ธ ๋ ์์๋ณด์. ์ ์ฝ๋๋ฅผ ์กฐ๊ธ ๋ ํ์ฅํ๋ค.
function Foo(name, menu) {
this.name = name
}
console.log(Foo.prototype.constructor == Foo) //true
let bar = new Foo('kelly')
console.log(bar.constructor === Foo) //true
ํด๋์ค์งํฅ์์ ๊ทธ๋ ๋ฏ์ด constructor๋ new ํค์๋๋ก ํธ์ถ ๋์ด ์ง๊ณ ์ธ์คํด์ค๋ฅผ ์ด๊ธฐํํ๋ค๊ณ ์๊ณ ์๋ค. ์์ bar ๊ฐ์ฒด๋ Foo์ ์ํด ์์ฑ๋์์ผ๋, constructor๊ฐ ํด๋์ค์งํฅ์์ ์๊ฐํ๋ ์์ฑ์๋ผ๊ณ ์๊ฐํ ์ ์์ง๋ง, ์นด์ผ์ฌ์จ์ "์์ฑ์์ ํ๋กํ ํ์ ์ด๋ ์ฉ์ด์์ฒด์ ์๋ฏธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋์จํ๊ธฐ ์ง์ด ์์ด์ ๋์ค์๋ ๋ถํฉํ์ง ์์ ๊ฐ๋ฅ์ฑ๋ ์๋ค. ์์ฑ์๋ '์์ฑ๋จ์ ์๋ฏธํ์ง ์๋๋ค.'" ๋ผ๊ณ ๋งํ๋ค. ์ฆ๋ช ์ ๋ณด๊ฒ ๋ค. ์์ ์ฝ๋์์ bar.constructor === Foo ๊ฐ true๋ฅผ ๋ฆฌํดํ์์ผ๋ฏ๋ก Foo()๊ฐ bar๋ฅผ ์์ฑํ ๊ฒ์ฒ๋ผ ๋ณผ ์ ์๋ค.
console.log(Foo.prototype.constructor == Foo) //true
Foo.prototype = {
age: 20,
}
let bar = new Foo('kelly')
console.log(bar.constructor === Foo) //false
ํ์ง๋ง, Foo.prototype ์ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ ์ ํ๋ ์๊ฐ, bar์ constructor ๋ ์์ด์ง๋ค. ๋์ด์ Foo๊ฐ ์๋๋ค. ์ ๊ทธ๋ด๊น?
constructor๊ฐ bar๊ฐ์ฒด ๋ด์ ์ค์ ์กด์ฌํ๋ ๊ฒ์ด ์๋๋ผ, Foo.prototype ๊ฐ์ฒด์ ์์ํ๊ธฐ ๋๋ฌธ์, Foo.prototype ์ ์๋ก์ด ๊ฐ์ฒด, ๋ค๋ฅธ ํ๋กํผํฐ๋ค๊ณผ ํจ๊ป ๋ฐ๋๋ฉด, constructor ํ๋กํผํฐ๊ฐ ๋น์ฐํ ์์ด์ง๋ฏ๋ก bar ๊ฐ์ฒด๊ฐ ๋น์ฐ ์ ๊ทผํ ์๊ฐ ์๋ค. ๊ทธ๋ฌ๋ฉด ์ด๋ฐ ๋ ผ๋ฆฌ์ ์ํ๋ฉด, bar.constructor๊ฐ ์ค์ ๊ธฐ๋ณธํจ์๋ฅผ ์ฐธ์กฐํ๋ ๋ ํผ๋ฐ์ค๋ผ๋ ๋ณด์ฅ์ด ์ ํ ์๋๋ฏ๋ก ๋ถ์์ ํ ๋ฟ๋๋ฌ, ์ง์ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข๋ค๊ณ ํ๋ค.
๋ ๊ฐ์ฒด๊ฐ์ ์์ ๋งํฌ ์์ฑ
function Vehicle(numberOfWheels) {
this.numberOfWheels = numberOfWheels
}
Vehicle.prototype.getNumberOfWheel = function () {
return this.numberOfWheels
}
function Car(arg) {}
Car.prototype = Object.create(Vehicle.prototype)
const tesla = new Car(4)
console.log(tesla.getNumberOfWheel()) //undefined
console.log(tesla.constructor === Car.prototype) //false
์ด๋ฒ์ฝ๋๋ ์์์ ์ธ๊ธํ๋ prototype์ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ํ ๋นํ๋ ๊ฒ๊ณผ ๋น์ทํ
์์ ์ด๋ค. ๋์ object๋ฅผ ์์ฑํ๋๋ฐ ๊ฐ์ฒด๋ฆฌํฐ๋ด์ด ์๋ ES05์ Object.create()
๋ฅผ ์ฌ์ฉํ์๋ค. Car.prototype์ ์๋ก์ด ๊ฐ์ฒด vehicle.prototype ์ ์ฐ๊ฒฐํ๋ค. ์ด๋ป๊ฒ? car.prototype ์ ๊ฐ์ฒด์ด๋ฏ๋ก,
prototype ํ๋กํผํฐ๊ฐ ์์ ๊ฒ์ด๊ณ , ์ด ๋ด๋ถ๋งํฌ๋ Object.create()์ ๋งค๊ฐ๋ณ์์ธ vehicle.prototype ๊ณผ ์ฐ๊ฒฐํ๋ค.
๊ทธ๋ผ Car()์ ์ํด ์์ฑ๋ ์ธ์คํด์ค tesla๋ Vehicle ๊ฐ์ฒด์ getNumberOfWheel()๋ฉ์๋์
์ ๊ทผํด๋ ๋์ง ์์๊น? ์ ๊ทผ์ ํ๋ฉด undefined๋ฅผ ๋ฆฌํดํ๋ค. ๊ทธ ์ด์ ๋ ์์์ ์ธ๊ธํ์๋ฏ์ด
Car.prototype์ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ํ ๋นํจ์ผ๋ก์จ tesla
์ constructor๋ ๋ ์ด์ Car.prototype ๊ณผ์ ์ฐ๊ฒฐ์ด ๋์ด์ ธ
Vehicle ๊ฐ์ฒด์ ๋ฉค๋ฒ ๋ณ์๋ ๋ฉ์๋์ ์ ๊ทผ์ ๋ชปํ๋ค. ์ด๋ฅผ ํด๊ฒฐ ํ ์ ์๋ ๋ฐฉ๋ฒ์ call ๋๋ apply๋ฅผ ์ฌ์ฉํ๋ค.
function Vehicle(numberOfWheels) {
this.numberOfWheels = numberOfWheels
this.engine = engine
}
Vehicle.prototype.getNumberOfWheel = function () {
return this.numberOfWheels
}
function Car(arg) {
Vehicle.call(this, arg)
}
Car.prototype = Object.create(Vehicle.prototype)
Car.prototype.identify = function () {
console.log(`This car has ${this.getNumberOfWheel()} wheels.`)
}
const tesla = new Car(4)
console.log(tesla.getNumberOfWheel())
tesla.identify() //This car has 4 wheels.
call์ Vehicle ํจ์๋ฅผ ์คํ์์ผ ์ฒซ๋ฒ์งธ ์ธ์์ธ this ๊ทธ๋ฌ๋๊น Car์ ์ธ์คํด์ค์ this๋ฅผ ๋ฐ์ธ๋ฉํ๋ค. tesla๋ฅผ callํ๊ธฐ์ ๊ณผ ํ๋ฅผ ๋น๊ตํด๋ณด๋ฉด,
- call() ํ๊ธฐ ์
Car์ ์ธ์คํด์ค์ธ tesla๋ Vehicle ํจ์ ๊ฐ์ฒด์ ๋ณ์๋ ๋ฉ์๋์ ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ฉฐ ์ด๊ฒ์ ๋ง์น ํด๋์ค
์งํฅ์ธ์ด์์์ ์์๊ณผ ๊ฐ์ ์์์ ๋๋ค. ํ์ง๋ง ์ฌ๊ธฐ์ ์ ๊ฒฝ์ ์จ์ค์ผ ํ ์ ์ Car.prototype ์ ์ ๊ฐ์ฒด๋ฅผ ํ ๋นํ
ํ๋ก Car.prototype.constructor
๊ฐ ์์ด์ก์ผ๋ฏ๋ก, Car.prototype์ ์ถ๊ฐํ ๋ฉ์๋๋ ๋ณ์๊ฐ ์๋ค๋ฉด,
์๋์ผ๋ก ํด๊ฒฐํด์ผ ํ๋ค. ES06์์ Object.setPrototypeOf(), Object.getPrototypeOf() ์ ์ฌ์ฉํ์ฌ
prototype ์ผ๋ก prototype ๊ฐ์ฒด๋ค์ ์ฐ๊ฒฐ ํ ์ ์๋ค. MDN์ prototype ์ค๋ช
์ ๋ฐ๋ฅด๋ฉด,
__proto__
์ deprecated ๋์๋ค๊ณ ๋์์๋ค. (Last modified: 2021๋
6์ 12์ผ)
prototype ํจ์จ์ฑ
ํจ์๊ฐ์ฒด์ prototype์ ์ด์ฉํ์ฌ ์์์ ๊ตฌํํ ๊ฒฝ์ฐ ๊ณตํต์ ์ผ๋ก ์ฌ์ฉ๋์ด์ง๋ ํด๋์ค ๋ฉค๋ฒ์ ๋ํด ์์๋ญ๋น๋ฅผ ์ค์ผ ์๊ฐ ์๋๋ฐ ์๋ฅผ ๋ค๋ฉด ์ด๋ ๋ค.
function Student(name, years) {
this.name = name
this.years = years
this.getName = function () {
return this.name
}
this.setName = function (arg) {
this.name = arg
}
}
let student1 = new Student('sue', 'sophomore')
let student2 = new Student('kelly', 'sophomore')
let student3 = new Student('kyle', 'junior')
console.log(student1.getName()) //sue
console.dir(student1)
console.dir(student2)
console.dir(Student)
function Student(name, years) {
this.name = name
this.years = years
}
Student.prototype.setName = function () {
this.name = value
}
Student.prototype.getName = function () {
return this.name
}
let student1 = new Student('sue', 'sophomore')
let student2 = new Student('kelly', 'sophomore')
let student3 = new Student('kyle', 'sophomore')
console.log(student1.getName()) //sue
console.dir(student1)
console.dir(student2)
console.dir(Student)
์ฒซ๋ฒ์งธ ์ฝ๋๋ฒ ์ด์ค์ ๋๋ฒ์งธ ์ฝ๋๋ฒ ์ด์ค์ ์ฐจ์ด์ ์ ํจ์๊ฐ์ฒด ๋ด์ ๋ฉค๋ฒ ๋ฉ์๋๋ฅผ ์ ์ธํ ๋, this๋ฅผ ์ด์ฉํ์ฌ ํจ์๊ฐ์ฒด ๋ด์ ์ ์ธํ๋๊ฐ์ ๋ฉค๋ฒ ํจ์๋ฅผ ํจ์๊ฐ์ฒด scope ๋ฐ์ ๋ฐ๋ก Student.prototype ์
์ฒด์ด๋์ผ๋ก ์ ๊ทผํ๋์ด๋ค. ๋ณด์ฌ์ง ์์์์๋ Student ๊ฐ์ฒดํจ์์ ์ธ์คํด์ค๊ฐ 3๊ฐ ๋ฟ์ด์ง๋ง ์ธ์คํด์ค๊ฐ 1000๊ฐ๋ผ๋ฉด, ๋งค ์ธ์คํด์ค ์์ฑ์, ๊ฐ ์ธ์คํด์ค ๋ง๋ค getName ,setName์ ์์ฑํ๊ฒ ๋๋ค. ์ด๋ค
์ธ์คํด์ค๋ getName ๊ณผ setName ์ ์ฌ์ฉํ์ง ์์ ์๋ ์๋ค. ์ด๋ฐ ์๋๋ฆฌ์ค๋ก ๋ฏธ๋ฃจ์ด ๋ณด์ ๋ถํ์ํ ์ค๋ณต๋ ์์๋ค์ด ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ผ๊ฐ ๊ฒ์์ ์ ์ ์๋ค. ์ด๋ฐ ์ํฉ์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ด prototype์
์ด์ฉํ๋ ๊ฒ์ด๊ณ ๋๋ฒ์งธ ์ฝ๋๊ฐ ์์์ด๋ค. Student์ ํจ์๊ฐ์ฒด์ ํ๋กํ ํ์
๊ฐ์ฒด์ ๋ฉค๋ฒ ํจ์๋ฅผ ์ ์ ํ์ฌ ํ์ฅ์ํจ๋ค.(Student.prototype.setName
)
๐this๋ฅผ ์ฌ์ฉํ ํด๋์ค ๋ฉค๋ฒ ํจ์
๐ ํ๋กํ ํ์ ์ฒด์ด๋
์์ ๋ค์ด์ด๊ทธ๋จ์์ ๋ณด์ฌ์ฃผ๋ฏ์ด, Student ํจ์๊ฐ์ฒด๋ก ์์ฑ๋ ์ธ์คํด์ค๋ค์ ๋ชจ๋ Student.prototype์ ๊ฐ๋ฆฌํค๊ธฐ ๋๋ฌธ์ prototype ์ฒด์ด๋์ผ๋ก Student.prototype์ ๋ฉค๋ฒํจ์์ ์ ๊ทผํ ์ ์๋ค.
๊ฒฐ๊ตญ Prototype ์์ ์๋ฐ์คํฌ๋ฆฝํธ์์์ ์์์ ๊ฐ๋ ์ ํด๋์ค๊ฐ์ฒด ์งํฅ ์ธ์ด์์์ ์์๊ณผ๋ ๋ค๋ฅธ ์๋ก์ ๊ฐ์ฒด๊ฐ์ ์ฒด์ด๋์ด๋ผ๊ณ ๋ณผ ์ ์์ผ๋ฉฐ, ๊ทธ ์ด๋ก ์ ๋ํ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ์ค๋ช ์ผ๋ก , new ๋ก ์์ฑ์ ํจ์๋ฅผ ํธ์ถํ ๋, ๊ฒฐ๊ตญ ๊ฐ์ฒด์ ๊ฐ์ฒด๋ฅผ ์ฐ๊ฒฐํ๋ค๋ ๊ฒ์ด๋ค. ๊ทธ๋์ ๊ฒฐ๊ตญ ์๋ฐ์คํฌ๋ฆฝํธ class๋ ํ๋กํ ํ์ ์ ์์์ฒด๊ณ์ ๊ธฐ๋ฐ์ ๋ ์ผ์ข ์ ๊ฐํธ๊ตฌ๋ฌธ์ด๋ค.
์ฐธ๊ณ ์๋ฃ
- [๋์ - ์นด์ผ ์ฌ์จ, YOU DON'T KNOW JS, ํ๋น ๋ฏธ๋์ด]
- [๋์ - ์กํ์ฃผ/๊ณ ํ์ค, ์ธ์ฌ์ด๋ ์๋ฐ์คํฌ๋ฆฝํธ, ํ๋น ๋ฏธ๋์ด ]
- [๋์ - ์ ์ง์ฑ, Quick start TypeScript, ๋ฃจ๋นํ์ด]
- MDN Prototype