class 기반의 패러다임을 가진 다른 OOP언어들과 다르게, 자바스크립트는 prototype 기반의 언어이며 prototypical inheritance라고도 불립니다.
모든 오브젝트는 숨겨진 내부 프로퍼티(inner property)인 [[Prototype]]
을 가지고 있습니다. 각 오브젝트는 그들의 constructor의 [[Prototype]] 부터 프로퍼티와 메소드를 상속받을 수 있습니다.
[[...]]
는 내부 프로퍼티를 의미하며 바로 접근할 수 없음getPrototypeOf()
혹은 .__proto__
를 사용해서 [[Prototype]]
에 접근Object.getPrototypeOf(x); // {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}
x.__proto__; // legacy
오브젝트의 프로퍼티 혹은 메소드에 접근할 때, 자바스크립트는 먼저 오브젝트에서 찾습니다. 만약 발견되지 않는다면 오브젝트의 [[Prototype]]
로부터 찾게 됩니다. 그 이후에도 찾아지지 않는다면 linked object의 prototype을 찾게 되고 이런식으로 쭉 올라가게 됩니다. 이러한 과정을 prototype chain
이라고 합니다. 모든 prototype chain의 끝은 Object.prototype
입니다.
예를들면,
1️⃣ const obj = {};
Object.prototype
으로부터 모든 프로퍼티를 상속받음obj
-> Object
2️⃣ const arr = [];
Array.prototype
으로부터 모든 프로퍼티를 상속받음y
-> Array
-> Object
Constructor functions은 새로운 오브젝트를 만들 수 있는 함수입니다.
constructor function에 기반한 새로운 인스탄스를 만들기 위해 new
키워드와 함께 사용합니다.
new Array()
, new Date()
등이 있음(예제1)
// Initialize a constructor function
function Hero(name, level) {
this.name = name;
this.level = level;
}
Hero.prototype.greet = function () {
return `${this.name} says hello.`;
}
let hero1 = new Hero('Bjorn', 1); // [[Prototype]]: Hero
hero1.greet(); // Bjorn says hello.
(예제2) Sub Constructor 생성
call()
을 사용해서 constructor에 chaining할 때, Prototype properties와 메소드는 자동적으로 연결이 되지 않는다. 따라서 Object.create()
를 사용해서 Constructor의 프로퍼티와 메소드를 상속받을 수 있도록 연결해줘야 한다.// Super Constructor
function Hero(name, level) {
this.name = name;
this.level = level;
}
// Sub Constructors
function Warrior(name, level, weapon) {
Hero.call(this, name, level);
this.weapon = weapon;
}
function Healer(name, level, spell) {
Hero.call(this, name, level);
this.spell = spell;
}
// Link prototypes and add prototype methods
Warrior.prototype = Object.create(Hero.prototype);
Healer.prototype = Object.create(Hero.prototype);
Hero.prototype.greet = function () {
return `${this.name} says hello.`;
}
Warrior.prototype.attack = function () {
return `${this.name} attacks with the ${this.weapon}.`;
}
Healer.prototype.heal = function () {
return `${this.name} casts ${this.spell}.`;
}
// Initialize individual character instances
const hero1 = new Warrior('Bjorn', 1, 'axe');
const hero2 = new Healer('Kanin', 1, 'cure');
hero1.greet(); // Bjorn says hello