자바스크립트는 클래스를 기반으로하는 전통적인 상속은 지원하지 않는다.
그러나 자바스크립트 특성중 프로토타입 체인을 이용하여 상속을 구현할 수 있다.
function createObject(o) {
function F() {}
F.prototype = o;
return new F();
}
위 세줄의 코드를 이해하면 프로토타입 기반의 상속을 다 배운것이나 다름없다.
createObject() 함수는 인자로 들어온 객체를 부모로 하는 자식 객체를 생성하여 반환하는 함수다.
- 새로운 빈 함수는 F를 만들고, F.prototye 프로퍼티에 인자로 들어온 객체를 참조한다.
- 그 다음 함수 객체 F를 생성자로 하는 새로운 객체를 만들어 반환한다.
이렇게 반환된 객체는 부모 객체의 프로퍼티에 접근할 수 있고, 자신만의 프로퍼티도 만들 수 있다.
var Blog = {
name : '',
getName : function() {
return this.name;
},
setName : function(name) {
this.name = name;
}
};
function createObject(o) {
function F() {};
F.prototype = o;
return new F();
}
var oppa = createObject(Blog);
oppa.setAge = function(age) { this.age = age; };
oppa.getAge = function (){ return this.age; };
oppa.setName('oppa');
oppa.setAge(25);
console.log(oppa.getName()); // 'oppa'
console.log(oppa.getAge()); // 25
Object.create()
ECMAScript 5판은 프로토타입 상속의 개념을 공식적으로 수용하여 Object.create() 메서드를 추가했다.
이 메서드는 매개변수를 두 개 받는데 하나는 다른 객체의 프로토타입이 될 객체이며, 옵션인 다른 하나는 새 객체에 추가할 프로퍼티를 담은 객체이다.
매개변수를 하나만 쓰면 위에서 만든 createObject() 함수도 똑같이 동작한다.
var Blog = {
name : '',
getName : function() {
return this.name;
},
setName : function() {
this.name = name;
}
};
// 두 번째 매개변수는 Object.defineProperties()의 두번 째 매개변수와 같은 형식이다.
// 즉, 추가할 프로퍼티마다 서술자와 함께 정의하는 형태다.
var oppa = Object.create(Blog, {
name : {
value : 'oppa'
}
});
console.log(oppa.getName()); // 'oppa'
프로토타입을 이용한 클래스 같은 상속
function Naver(name) {
this.name = name;
}
Naver.prototype.setName = function(name) {
this.name = name;
};
Naver.prototype.getName = function() {
return this.name;
}
function Blog(arg) {
};
var naver = new Naver('oppa');
Blog.prototype = naver;
var oppacoidng = new Blog('coding');
oppacoding.setName('coding');
console.log(oppacoding.getName()); // 'coding'
Blog 함수 객체를 만들어서, 이 함수 객체의 프로토타입으로 하여금 Naver 함수 객체의 인스턴스를 참조하게 만들었다.
- 생성자
그러나 Blog 생성자 함수의 인스턴스를 생성할 때 부모 클래스인 Naver 생성자 함수의 생성자를 호출하지 않는 문제가 있다.
결국 setName() 메서드가 호출 되고 나서야 oppacoding 객체에 name 프로퍼티가 만들어진다. 이럴 경우 부모의 생성자가 호출되지 않으면, 인스턴스 초기화가 이루어지 않아 문제가 발생할 수 있다.
아래와 같은 코드로 자식 클래스의 인스턴스에 대해서도 부모 클래스의 생성자를 실행시킬 수 있다.
function Blog(arg) {
Naver.apply(this, arguments);
}
// Blog 함수 안에서 새롭게 생성된 객체를 apply 함수의 첫 번째 인자로 넘겨 Naver 함수를 실행시킨다.
- 독립
자식 클래스의 객체가 부모 클래스의 객체를 프로토타입으로 직접 접근한다.
하지만 부모 클래스의 인스턴스와 자식 클래스의 인스턴스는 서로 독립적일 필요가 있다.
두 클래스의 프로토타입 사이에 중개자를 하나 만들어 보겠다.
function Naver(name) {
this.name = name;
}
Naver.prototype.setName = function(name) {
this.name = name;
};
Naver.prototype.getName = function() {
return this.name;
}
function Blog(arg) {
};
function inherit = function(parent, child) {
var F = function() {};
return function(parent, child) {
F.prototype = parent.prototype;
child.prototype = new F();
child.prototype.constructor = child;
child.super = parent.prototye;
};
}
inherit(Naver, Blog);
var oppacoidng = new Blog('coding');
oppacoding.setName('coding');
console.log(oppacoding.getName()); // 'coding'
빈 함수 객체를 중간에 두어 Naver의 인스턴스와 Blog의 인스턴스를 서로 독립적으로 만들었다.
이제 Naver 함수 객체에서 this에 바인딩 되는 것은 Blog의 인스턴스가 접근할 수 없다.
by 소년코딩
추천은 글쓴이에게 큰 도움이 됩니다.
악플보다 무서운 무플, 댓글은 블로그 운영에 큰 힘이됩니다.