상속은 객체 지향 프로그래밍에서 객체 간의 코드 및 속성을 공유하기 위한 메커니즘이며, 보통은 상위와 하위 객체의 관계를 부모-자식 관계에 빗대어 표현한다. 다른 말로 하면, 상속은 객체의 로직을 그대로 물려 받는 또 다른 객체를 만들 수 있는 기능을 의미한다. 단순히 물려받는 것이 아닌 기존의 로직을 수정하고 변경해서 파생된 새로운 객체를 만들 수 있게 해준다. 아래는 자바스크립트에서의 상속을 구현한 짧은 코드이다.
function Person(name) {
this.name = name;
}
Person.prototype.name=null;
Person.prototype.introduce = function () {
return 'My name is ' + this.name;
}
var p1 = new Person("Lee"); // My name is Lee
console.log(p1.introduce());
function Employee(name, position){
this.name = name;
this.position=position;
}
Employee.prototype = new Person();
Employee.prototype.getDetails = function() {
return this.introduce() + ' and I work as a ' + this.position;
};
var emp = new Employee('John Doe', 'Manager');
console.log(emp.getDetails()); // My name is John Doe and I work as a Manager
Employee이라는 생성자를 만든 뒤, 이 생성자의 prototype과 Person의 객체를 연결했더니 Employee 객체도 메소드 introduce를 사용할 수 있게 되었고, 자신만의 프로퍼티도 사용할 수 있게 되었다. 그 결과 "My name is John Doe and I work as a Manager" 이 콘솔에 출력되었다. 좀더 자세히 설명하자면,
function Person(name) {
this.name = name;
}
Person.prototype.name=null;
Person.prototype.introduce = function () {
return 'My name is ' + this.name;
}
var p1 = new Person("Lee"); // My name is Lee
console.log(p1.introduce());
function Employee(name, position){
this.name = name;
this.position=position;
}
Employee.prototype = new Person();
Employee.prototype.getDetails = function() {
return this.introduce() + ' and I work as a ' + this.position;
};
var emp = new Employee('John Doe', 'Manager');
console.log(emp.getDetails()); // My name is John Doe and I work as a Manager
이상의 상속과 관련하여 중요한 개념은 프로토타입(prototype)과 프로토타입 체인(prototype chain)이다. 위의 코드를 좀더 이해하기 위해선 이 두 개념에 대해 알아야 한다.
프로토타입(prototype)은 객체 지향 프로그래밍에서 객체 간의 상속과 프로퍼티 공유를 구현하기 위한 메커니즘이다.
모든 JavaScript 객체는 프로토타입을 가지며, 프로토타입은 다른 객체로써 동작할 수 있다. 프로토타입은 말 그대로 객체의 원형이라고 할 수 있다. 함수는 객체이며, 생성자로 사용될 함수도 객체이다. 객체는 프로퍼티를 가질 수 있는데 prototype이라는 프로퍼티는 그 용도가 약속되어 있는 특수한 프로퍼티이다. prototype에 저장된 속성들은 생성자를 통해서 객체가 만들어질 때 그 객체에 연결된다. 객체는 프로토타입을 통해 프로퍼티와 메서드를 상속받고, 이를 통해 코드의 재사용성과 구조화를 촉진할 수 있다.
객체를 생성할 때, 객체 리터럴 {}이나 new 키워드를 사용하여 생성한 객체는 기본적으로 Object.prototype을 프로토타입으로 가진다. 즉, 모든 객체는 Object.prototype에 정의된 메서드와 프로퍼티를 상속받는다. 예를 들어, toString()이나 hasOwnProperty()과 같은 메서드는 Object.prototype에 정의되어 있으며, 모든 객체가 이를 사용할 수 있다.
프로토타입을 이해하기 위해 아래 예시를 보자.
function Ultra(){};
Ultra.prototype.ultraProp = true;
function Super(){};
Super.prototype = new Ultra();
function Sub(){};
Sub.prototype = new Super();
var o = Sub();
console.log(o.ultraProp); //true
생성자 Sub를 통해서 만들어진 객체 o가 Ultra의 프로퍼티 ultraProp에 접근 가능한 것은 prototype 체인으로 Sub와 Ultra가 연결되어 있기 때문이다. 내부적으로는 아래와 같은 일이 일어난다.
프로토타입(prototype)은 객체와 객체를 연결하는 체인의 역할을 하는 것이다. 이러한 관계를 prototype chain이라고 한다