์๋ฐ์คํฌ๋ฆฝํธ ํ๋กํ ํ์ ์ฒด์ด๋ ์๋ฒฝ ๊ฐ์ด๋
์๋ฐ์คํฌ๋ฆฝํธ ํ๋กํ ํ์ ์ฒด์ด๋์ ํต์ฌ ๊ฐ๋ ๋ถํฐ ์ค์ ํ์ฉ๊น์ง! ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ธ ์์ ๊ตฌ์กฐ์ 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}๊ฐ ์๋ฆฌ๋ฅผ ๋
๋๋ค.`);
};
์๋ฐ์คํฌ๋ฆฝํธ์์๋ ๋ชจ๋ ๊ฐ์ฒด๊ฐ ๋ค๋ฅธ ๊ฐ์ฒด๋ก๋ถํฐ ์ง์ ์์๋ฐ์ ์ ์์ต๋๋ค. ์ด๊ฒ์ด ๋ฐ๋ก ํ๋กํ ํ์ ๊ธฐ๋ฐ ํ๋ก๊ทธ๋๋ฐ์ ํต์ฌ์ด์์.
ํ๋กํ ํ์ ๊ธฐ๋ฐ ํ๋ก๊ทธ๋๋ฐ์ด๋?
ํ๋กํ ํ์ ๊ธฐ๋ฐ ํ๋ก๊ทธ๋๋ฐ์ ํด๋์ค ์์ด๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์์์ ๊ตฌํํ ์ ์๋ ํ๋ก๊ทธ๋๋ฐ ํจ๋ฌ๋ค์์ ๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ชจ๋ ๊ฐ์ฒด๋ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ ์ ์๋ ์จ๊ฒจ์ง ๋งํฌ๋ฅผ ๊ฐ์ง๊ณ ์์ด์.
ํ๋กํ ํ์ ๊ธฐ๋ฐ ํ๋ก๊ทธ๋๋ฐ์ ํน์ง
- ๋์ ์์: ์คํ ์๊ฐ์ ๊ฐ์ฒด์ ํ๋กํ ํ์ ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
- ์ ์ฐ์ฑ: ํด๋์ค ์ ์ธ ์์ด๋ ๊ฐ์ฒด ๊ฐ ์์ ๊ด๊ณ๋ฅผ ๋ง๋ค ์ ์์ด์.
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ: ๊ณตํต ๋ฉ์๋๋ฅผ ํ๋กํ ํ์ ์์ ๊ณต์ ํ์ฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ฝํ ์ ์์ต๋๋ค.
// ํ๋กํ ํ์
๊ธฐ๋ฐ ์์ ์์
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
ํ๋กํ ํ์ ์ฒด์ด๋์ ๋์ ์๋ฆฌ
ํ๋กํ ํ์ ์ฒด์ด๋์ ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ๊ฐ์ฒด์ ํ๋กํผํฐ๋ ๋ฉ์๋๋ฅผ ์ฐพ๋ ๋ฉ์ปค๋์ฆ์ ๋๋ค. ํด๋น ๊ฐ์ฒด์ ์ํ๋ ํ๋กํผํฐ๊ฐ ์์ผ๋ฉด, ํ๋กํ ํ์ ์ฒด์ธ์ ๋ฐ๋ผ ์ฌ๋ผ๊ฐ๋ฉด์ ์ฐพ์์.
ํ๋กํผํฐ ๊ฒ์ ๊ณผ์
- ๋จผ์ ๊ฐ์ฒด ์์ ์ ํ๋กํผํฐ์์ ๊ฒ์
- ์์ผ๋ฉด
__proto__๊ฐ ๊ฐ๋ฆฌํค๋ ํ๋กํ ํ์ ๊ฐ์ฒด์์ ๊ฒ์ - ์ฌ์ ํ ์์ผ๋ฉด ๊ทธ ํ๋กํ ํ์ ์ ํ๋กํ ํ์ ์์ ๊ฒ์
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
ํ๋กํ ํ์ ์ฒด์ด๋ ๋ง์คํฐํ๊ธฐ
ํ๋กํ ํ์ ์ฒด์ด๋์ ์๋ฐ์คํฌ๋ฆฝํธ์ ํต์ฌ ๊ฐ๋ ์ค ํ๋์ ๋๋ค. ์ด๋ฅผ ์ ๋๋ก ์ดํดํ๋ฉด ๋ ํจ์จ์ ์ด๊ณ ์ ์ฐํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ด์.
ํต์ฌ ํฌ์ธํธ๋ฅผ ์ ๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ํ๋กํ ํ์ ๊ธฐ๋ฐ ์์: ์๋ฐ์คํฌ๋ฆฝํธ๋ ํด๋์ค ๊ธฐ๋ฐ์ด ์๋ ํ๋กํ ํ์ ๊ธฐ๋ฐ ์์์ ์ฌ์ฉํฉ๋๋ค.
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ: ํ๋กํ ํ์ ์ ํ์ฉํ๋ฉด ๋ฉ์๋๋ฅผ ๊ณต์ ํ์ฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ฝํ ์ ์์ด์.
- ๋์ ํน์ฑ: ์คํ ์๊ฐ์ ํ๋กํ ํ์ ์ ๋ณ๊ฒฝํ ์ ์์ด ๋งค์ฐ ์ ์ฐํ ํ๋ก๊ทธ๋๋ฐ์ด ๊ฐ๋ฅํฉ๋๋ค.
- ์ฒด์ธ ํ์: ํ๋กํผํฐ ๊ฒ์ ์ ํ๋กํ ํ์ ์ฒด์ธ์ ๋ฐ๋ผ ์ฌ๋ผ๊ฐ๋ฉฐ ๊ฒ์ํ๋ ๋ฉ์ปค๋์ฆ์ ์ดํดํด์ผ ํด์.
- ์์ ํ ์ฌ์ฉ:
Object.getPrototypeOf,Object.setPrototypeOf,Object.create๋ฑ์ ๋ฉ์๋๋ฅผ ํ์ฉํ์ฌ ์์ ํ๊ฒ ํ๋กํ ํ์ ์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
ํ๋กํ ํ์ ์ฒด์ด๋์ ๋ง์คํฐํ๋ฉด ES6 ํด๋์ค ๋ฌธ๋ฒ๋ ๋ ๊น์ด ์๊ฒ ์ดํดํ ์ ์๊ณ , ์๋ฐ์คํฌ๋ฆฝํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ๋ ์์ํฌ์ ๋ด๋ถ ๋์ ์๋ฆฌ๋ ํ์ ํ๊ธฐ ์ฌ์์ง๋๋ค. ์ค๋ฌด์์ ๋ง์ฃผ์น๋ ๋ณต์กํ ์์ ๊ตฌ์กฐ๋ ๋์์ธ ํจํด๋ ์์ ์๊ฒ ๋ค๋ฃฐ ์ ์์ ๊ฑฐ์์.
์ง๊ธ๋ถํฐ ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ์์ ํ๋กํ ํ์ ์ฒด์ด๋์ ์ ๊ทน ํ์ฉํด๋ณด์ธ์. ๋ ๊น๋ํ๊ณ ํจ์จ์ ์ธ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ ๊ฒ์ ๋๋ค!