ES6 로 넘어오며 class개념을 등장시켜 적극적으로 객체 지향을 지원하기 전까지, 객체 지향 프로그래밍 구현에 가장 자주 쓰였던 방식은 pseudoclassical inheritance 방식이다.
💡pseudoclassical inheritance
사전을 찾아보면 pseudo 는 '가짜의' 라는 의미가 있다.
pseudoclassical inheritance 는 가짜로 class 개념을 흉내내는 상속 방식 이라는 뜻인 것 같다.(아마도?)
✍️부모 생성자 함수의 프로토 타입을 자식 생성자 함수의 프로토 타입으로 설정해보자.
function Parent(name, age) {
this.name = name;
this.age = age;
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child(name, age) {
this.name = name;
this.age = age;
}
Child.prototype = Parent.prototype;
const parent = new Parent("지영", 35);
parent.sayName(); // 지영
const child = new Child("철수", 2);
child.sayName(); // 철수
✍️ 자식 생성자 함수의 프로토타입에 부모 생성자 함수의 프로토타입을 가지고 있는 객체를 대입해보자.
function Parent(name, age) {
this.name = name;
this.age = age;
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
Child.prototype = { ...Parent.prototype };
Child.prototype.sleep = function() {
console.log("....zzZ");
};
const parent = new Parent("지영", 35);
parent.sayName(); // 지영
parent.sleep(); // TypeError: parent.sleep is not a function
const child = new Child("철수", 2);
child.sayName(); // 철수
child.sleep(); // ....zzZ
Parent.prototype
을 넣어준다.Parent.prototype
에 정의된 값을 사용할 수 있다.Child.prototype = { ...Parent.prototype };
Child.prototype.sleep = function() {
console.log("....zzZ");
};
Parent.prototype.sayHello = function() {
console.log("hello");
};
const parent = new Parent("jane", 35);
parent.sayName(); // jane
parent.sayHello(); // hello
const child = new Child("john", 2);
child.sayName(); // john
child.sleep(); // ....zzZ
child.sayHello(); // TypeError: parent.sleep is not a function
-> 참조가 끊겨 Parent.prototype
을 참조하지 못하기 때문에 자식 생성자 함수의 프로토타입에는 새로운 메서드가 전달되지 못한다.
그렇다면 우리는 어떤 방식을 써서 상속 시켜줘야 할까?
✍️ 바로 Object.create(prototype)
메서드를 사용하는 방법이 있다.
메서드의 첫번째 인자에는 새로 만든 객체의 __proto__
가 가리킬 prototype
을 입력한다.
function Parent(name, age) {
this.name = name;
this.age = age;
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
Child.prototype = Object.create(Parent.prototype);
Child.prototype.sleep = function() {
console.log("....zzZ");
};
Parent.prototype.sayHello = function() {
console.log("hello");
};
const parent = new Parent("지영", 35);
parent.sayName(); // 지영
parent.sayHello(); // hello
const child = new Child("철수", 2);
child.sayName(); // 철수
child.sleep(); // ....zzZ
child.sayHello(); // hello
Object.create(prototype)
메소드를 호출하여 상속하는 방법은 원하는대로 상속이 되긴 했지만 완벽한 상속 관계를 위해 수정해줘야 할 부분이 있다.console.log(child.__proto__.constructor); // function Parent() {}
-> 우리가 child.proto.constructor 으로 기대한 생성자 함수는 Child이다.
Child.prototype.constructor = Child;
console.log(child.__proto__.constructor); // function Child() {}
✍️ 부모 생성자에게서 상속 받을 속성이 있다면 부모생성자.call(this)
또는 부모생성자.apply(this,arguments)
를 사용해 상속을 받아 그대로 사용하거나 또는 새로운 값을 할당할 수 있다.
// Case1
function Child(name, age) {
// ~~~~
}
const child = new Child("지영", 2);
child.sayName(); // undefined
// ---------------------------------
// Case2
function Child(name, age) {
Parent.apply(this, arguments);
}
const child = new Child("철수", 2);
child.sayName(); // 철수
- 자식 생성자 함수 안에서 call/apply 를 통해 부모 생성자 함수와 연결시킨다.
- 자식 생성자 함수의 prototype 객체를 Object.create 메소드를 통해 부모 생성자 함수의 prototype 과 연결시킨다.
- 자식 생성자 함수의 constructor 를 자기 자신으로 재할당해준다.
constructor
로 정의하고 속성값을 세팅한다.extends
키워드를 사용해 상속 받을 수 있다.call
메소드나 apply
메소드를 사용해야 하는데,super
라는 키워드를 사용하면 쉽게 부모 클래스의 속성 값을 상속받아 사용할 수 있다.✍️ 위의 pseudoclassical inheritance 방식 코드를 클래스 방식으로 수정해 보자.
class Parent {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
console.log(this.name);
}
sayHello() {
console.log("Hello!");
}
}
class Child extends Parent {
constructor(name, age) {
super(name, age);
}
sleep() {
console.log("....zzZ");
}
}
const parent = new Parent("지영", 30);
const child = new Child("철수", 2);
parent.sayName(); // 지영
parent.sayHello(); // Hello!
parent.sleep(); // TypeError: parent.sleep is not a function
child.sayName(); // 철수
child.sayHello(); //Hello!
child.sleep(); // ....zzZ
class Parent {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
console.log(this.name);
}
sayHello() {
console.log("Hello!");
}
}
class Child extends Parent {
sleep() {
console.log("....zzZ");
}
}
const parent = new Parent("지영", 30);
const child = new Child("철수", 2);
parent.sayName(); // 지영
parent.sayHello(); // Hello!
parent.sleep(); // TypeError: parent.sleep is not a function
child.sayName(); // 철수
child.sayHello(); //Hello!
child.sleep(); // ....zzZ