Chapter 4: Mixing (Up) "Class" Objects - hochan222/Everything-in-JavaScript GitHub Wiki
์์ ๋จ์ object๋ฅผ ์ ํ๋ฉด ๊ฐ์ฒด์งํฅํ๋ก๊ทธ๋๋ฐ(object oriented (OO) programming)์ ๋ ์ฌ๋ฆฌ๋๊ฑด ์์ฐ์ค๋ฐ ์ผ์ด๋ค. class์ ์ธ์คํด์คํ(instantiation), ์์(inheritance), ๋คํ์ฑ(polymorphism)์ ๋ณด๊ธฐ์ ์ ๋จผ์ ๋์์ธ ํจํด์ผ๋ก์จ์ "class orientation"์ ๋ณด์.
Class Theory
ํด๋ผ์ค ์์์ ์ํํธ์จ์ด์์ ์ค์ ๋ฌธ์ ๋ค์ ๋ชจ๋ธ๋งํ๋ ์ํคํ ์ณ์ด๋ค. ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ๊ธฐ๋ณธ ๋์์ ๋ฐ์ดํฐ๊ฐ ์๋ํ๋ ๊ด๋ จ ๋์์ ๋ณธ์ง์ ์ผ๋ก ๊ฐ์ง๊ณ ์๋ค. ์ฐ๋ฆฌ๋ ์ด๊ฒ์ ์๋ฃ ๊ตฌ์กฐ๋ผ๊ณ ๋ ๋ถ๋ฅธ๋ค. ํด๋์ค๋ ํน์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๋ถ๋ฅํ๋ ๋ฐฉ๋ฒ์ ์๋ฏธํ๋ค. ์๋ฅผ๋ค์ด ์๋์ฐจ๋ ์ฐจ๋์ด๋ผ๋ ์ผ๋ฐ์ ์ธ class์ ํน์ ๊ตฌํ์ผ๋ก ์ค๋ช ํ ์ ์๋ค. Vehicle Class(๋นํ๊ธฐ, ์๋์ฐจ ํ๊ฒ๋ฑ๋ฑ)์ Car Class(์์ง, ์์ ๋ฑ๋ฑ)๋ฅผ ์ ์ํ์ฌ ์ํํธ์จ์ด์์ ํด๋์ค์์ด ๊ด๊ณ๋ฅผ ๋ชจ๋ธ๋งํ ์ ์๋ค.
๋ณธ์ง์ ๋ฐ๋ณตํด์ ๋ค์ ์ ์ํ๋ ๊ฒ์ ์ํํธ์จ์ด์์ ์๋ฏธ๊ฐ ์๋ค. ๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ ์์์ ์ฌ์ฉํ๋ค. Class๋ ์ด๊ฒ๋ค์ ์งํฉ์ ์ผ๋ก ์ ์ํ์ง๋ง ์ธ์คํด์คํ๋ ๊ฐ๋ณ ๊ณ ์ ์ ๊ฒ์ผ๋ก ์ ์ํ๋ค.
Class์ ๋ ๋ค๋ฅธ ํน์ฑ์ ๋คํ์ฑ์ผ๋ก ๋ถ๋ชจ Class์ ์ผ๋ฐ์ ๋์์ ์์ Class์์ ์ฌ์ ์ํด์ ์ ๊ณต ํ ์ ์๋ค.
"Class" Design Pattern
"Iterator", "Observer", "Factory", "Singleton"์ "OO Design Patterns"์ผ๋ก ํ ๋ก ํ๋ ๊ฑฐ์ฌ ์ฃผ๋ก ๋ณด์๊ธฐ์ OO class๋ค์ ๋์์ธ ํจํด์ผ๋ก ์๊ฐํ์ง ์์์ ๊ฒ์ด๋ค. ํ์ง๋ง class๋ ๋ชจ๋ ๊ฒ์ ํฌํจ ํ ์ ์๋ ๋ฎ์ ์์ค์ ๋์์ธ ํจํด์ด๋ค.
JavaScript "Classes"
Javascript๊ฐ class ๋ฌธ๋ฒ์ ์ค์ ์ ์ผ๋ก ๊ฐ๊ณ ์๋๊ฐ? ์๋๋ค.
JS๋ ํด๋์ค์ ์ ์ฌํ ๊ตฌ๋ฌธ์ ์ ๊ณตํ์ฌ Class๋ฅผ ๋์์ธํ๋ ค๋ ์๊ตฌ๋ฅผ ์ถฉ์กฑ์์ผ์ค๋ค. ํ๋ง๋๋ก JS์์ ํด๋ผ์ค๋ ๊ฐ์ง๋ค.
Class Mechanics
๋ง์ ํด๋ผ์ค ์งํฅ ์ธ์ด์์ ์๋ฃ๊ตฌ์กฐ์ธ ์คํ์ ํด๋ผ์ค๋ก ์ ๊ณตํ๊ณ ์๋ค. ๊ทธ๋ฌ๋ ์ธ์ด์์ ์ค์ ๋ก ์คํ์์ ์ง์ ์์ ํ์ง ์๋๋ค. ์คํ ํด๋ผ์ค๋ ์ถ์์ ์ธ ์ค๋ช ์ ๋ถ๊ณผํ๊ณ ๊ตฌ์ฒด์ ์ธ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ผ๋ ค๋ฉด ์ธ์คํด์คํ ํด์ผํ๋ค.
Building
์ฐ๋ฆฌ๋ ์ค์ ๋ก ์ํธ์์ฉ ํ ์ ์๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ธฐ์ํด ํด๋ผ์ค๋ฅผ ๋น๋(์ธ์คํด์คํ)ํ๋ฉฐ ์ธ์คํด์ค(๊ฐ์ฒด)๋ฅผ ์ป๋๋ค. ๋ํ, ํ์์๋ฐ๋ผ ์ด๋ฅผ ํตํด ๋ฉ์๋์ ๊ณต๊ฐ ๋ฐ์ดํฐ ์์ฑ์ ์ ๊ทผ ํ ์ ์๋ค.
Constructor
ํด๋์ค์ ์ธ์คํด์ค๋ ์์ฑ์๋ผ๊ณ ํ๋ ํด๋ผ์ค์ ๋์ผํ ์ด๋ฆ์ ํด๋ผ์ค์ ํน์ ๋ฉ์๋์ ํจ๊ป ๊ตฌ์ฑ๋๋ค. ์ด ๋ฉ์๋์ ๋ช ์์ ์์ ์ ์ธ์คํด์ค์ ํ์ํ ์ ๋ณด(์ํ)๋ฅผ ์ด๊ธฐํ ํ๋๊ฒ์ด๋ค.
๋ค์ ์์ฌ์ฝ๋๋ฅผ ๋ณด์.
class CoolGuy {
specialTrick = nothing
CoolGuy( trick ) {
specialTrick = trick
}
showOff() {
output( "Here's my trick: ", specialTrick )
}
}
Joe = new CoolGuy( "jumping rope" )
Joe.showOff() // Here's my trick: jumping rope
Class Inheritance
์์ ์์ฌ์ฝ๋
class Vehicle {
engines = 1
ignition() {
output( "Turning on my engine." )
}
drive() {
ignition()
output( "Steering and moving forward!" )
}
}
class Car inherits Vehicle {
wheels = 4
drive() {
inherited:drive()
output( "Rolling on all ", wheels, " wheels!" )
}
}
class SpeedBoat inherits Vehicle {
engines = 2
ignition() {
output( "Turning on my ", engines, " engines." )
}
pilot() {
inherited:drive()
output( "Speeding through the water with ease!" )
}
}
Polymorphism
JS์์ ์์๊ณผ ๋ถ๋ชจ ์ฌ์ด์ ๊ด๊ณ๋ ๊ฐ ์์ฑ์์ ๋ prototype ๊ฐ์ฒด ์ฌ์ด์๋ง ์กด์ฌํ๊ธฐ ๋๋ฌธ์ ์์ฑ์ ์์ฒด๋ ์ง์ ๊ด๋ จ์ด ์๋ค.
ํด๋์ค๊ฐ ์์ ๋ ๋ ํด๋์ค ์์ฒด(ํด๋์ค์์ ์์ฑ ๋ ๊ฐ์ฒด ์ธ์คํด์ค๊ฐ ์๋๋ค.)๊ฐ ์์ ๋ ํด๋์ค๋ฅผ ์๋์ ์ผ๋ก ์ฐธ์กฐํ ์์๋ ๋ฐฉ๋ฒ์ด ์์ผ๋ฉฐ ์ด ์๋ ์ฐธ์กฐ๋ฅผ ์ผ๋ฐ์ ์ผ๋ก super๋ผ๊ณ ํ๋ค.
๋คํ์ฑ์ ๋ถ๋ชจ์ ์์์ด ์ฐ๊ฒฐ๋ผ์๋๊ฒ ์๋๊ณ ์์ ํด๋์ค์์ ๋ถ๋ชจ ํด๋์ค๋ก๋ถํฐ ๋ณต์ฌ๋ณธ์ ๊ฐ์ ธ์จ๋ค. ํด๋์ค ์์์ ๋ณต์ฌ๋ณธ์ ์๋ฏธํ๋ค.
Multiple Inheritance
Javascript๋ "๋ค์ค ์์"์ ์ํ ๊ธฐ๋ณธ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ง ์๋๋ค.
Mixins
JavaScript์ ๊ฐ์ฒด ๋ฉ์ปค๋์ฆ์ "์์"๋๋ "์ธ์คํด์คํ"ํ ๋ ์๋์ผ๋ก ๋ณต์ฌ ๋์์ ์ํํ์ง ์๋๋ค. ์๋ฐ ์คํฌ๋ฆฝํธ์๋ ๊ฐ์ฒด๋ฅผ ์ธ์คํด์คํํ๋ ํด๋์ค๊ฐ ์๋ค. ๊ฐ์ฒด๋ ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ณต์ฌ๋์ง ์๊ณ ์๋ก ์ฐ๊ฒฐ๋๋ค.
๋ค๋ฅธ ์ธ์ด์์ ํด๋์ค ๋์์ ๋ณต์ฌ๋ฅผ ์๋ฏธํ๋ค. ๋ฐ๋ผ์, JS ๊ฐ๋ฐ์๊ฐ JavaScript์์ ํด๋์ค์ ๋๋ฝ ๋ ๋ณต์ฌ ๋์์ mixins์ ํตํด ์ ์ฌ ๋์์ ๊ตฌํํ๋ค.
๋ช ์์ , ์์์ mixin์ ์ดํด๋ณด์.
Explicit Mixins
์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ณต์ฌ๋ฅผ ํ์ง ์์์ผ๋ก ๊ฐ์ ๋์์ผ๋ก extend()๋ผ๊ณ ๋ถ๋ฆฌ๊ณ ์๋ mixin์ ๋ง๋ค์ด๋ณด์.
// vastly simplified `mixin(..)` example:
function mixin( sourceObj, targetObj ) {
for (var key in sourceObj) {
// only copy if not already present
if (!(key in targetObj)) {
targetObj[key] = sourceObj[key];
}
}
return targetObj;
}
var Vehicle = {
engines: 1,
ignition: function() {
console.log( "Turning on my engine." );
},
drive: function() {
this.ignition();
console.log( "Steering and moving forward!" );
}
};
var Car = mixin( Vehicle, {
wheels: 4,
drive: function() {
Vehicle.drive.call( this );
console.log( "Rolling on all " + this.wheels + " wheels!" );
}
} );
๊ธฐ์ ์ ์ผ๋ก ํจ์๋ ์ค์ ๋ก ๋ณต์ฌ๊ฐ ๋์ง์๊ณ ์ฐธ์กฐ๊ฐ ๋ณต์ฌ๋๋ค.
"Polymorphism" Revisited
JavaScript์๋ ์๋ ๋คํ์ฑ์ ์ํ ๊ธฐ๋ฅ์ด ์๋ค. ๋ฐ๋ผ์ Car์ Vehicle ๋ชจ๋ ๊ฐ์ ์ด๋ฆ์ ํจ์๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ํ๋ ๋๋ ๋ค๋ฅธ ํธ์ถ์ ๊ตฌ๋ณํ๊ธฐ ์ํด ์ ๋ ์ฐธ์กฐ๋ฅผ ๋ง๋ค์ด์ผํ๋ค.
Parasitic Inheritance
์ด ๋ฐฉ๋ฒ์ ์ด๋ค ๋ฉด์์๋ ๋ช ์์ ์ด๊ณ ์ด๋ค ๋ฉด์์๋ ์์์ ์ด๋ค. Douglas Crockford์ ์ํด ๋์คํ๋๋ค.
// "Traditional JS Class" `Vehicle`
function Vehicle() {
this.engines = 1;
}
Vehicle.prototype.ignition = function() {
console.log( "Turning on my engine." );
};
Vehicle.prototype.drive = function() {
this.ignition();
console.log( "Steering and moving forward!" );
};
// "Parasitic Class" `Car`
function Car() {
// first, `car` is a `Vehicle`
var car = new Vehicle();
// now, let's modify our `car` to specialize it
car.wheels = 4;
// save a privileged reference to `Vehicle::drive()`
var vehDrive = car.drive;
// override `Vehicle::drive()`
car.drive = function() {
vehDrive.call( this );
console.log( "Rolling on all " + this.wheels + " wheels!" );
};
return car;
}
var myCar = new Car();
myCar.drive();
// Turning on my engine.
// Steering and moving forward!
// Rolling on all 4 wheels!
Implicit Mixins
var Something = {
cool: function() {
this.greeting = "Hello World";
this.count = this.count ? this.count + 1 : 1;
}
};
Something.cool();
Something.greeting; // "Hello World"
Something.count; // 1
var Another = {
cool: function() {
// implicit mixin of `Something` to `Another`
Something.cool.call( this );
}
};
Another.cool();
Another.greeting; // "Hello World"
Another.count; // 1 (not shared state with `Something`
Review (TL;DR)
ํด๋ผ์ค๋ ๋์์ธ ํจํด์ด๋ค.
ํด๋ผ์ค๋ ๋ณต์ฌ๋ฅผ ์๋ฏธํ๋ค.
์ ํต์ ์ธ ํด๋์ค๊ฐ ์ธ์คํด์คํ๋๋ฉด ํด๋์ค์์ ์ธ์คํด์ค๋ก ๋์์ ๋ณต์ฌ๋ณธ์ด ๋ฐ์ํ๊ณ , ํด๋์ค๊ฐ ์์๋๋ฉด ๋ถ๋ชจ์์ ์์์ผ๋ก์ ๋์ ๋ณต์ฌ๋ณธ๋ ๋ฐ์ํ๋ค.
๋คํ์ฑ๋ ๋ณต์ฌ๋์์ ๊ฒฐ๊ณผ์ด๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ฐ์ฒด์ฌ์ด์์ ์๋์ ์ผ๋ก ๋ณต์ฌ๋ณธ์ ์์ฑํ์ง ์๋๋ค.