Javascript 객체 고급 : 생성자를 통한 상속
자바스크립트의 상속에는 객체와 객체가 직접상속하는 방법, class 또는 constructor function 을 통한 상속이 있다.
생성자를 통한 상속 - 부모 생성자 실행
class Person{
constructor(name, first, second){
this.name = name;
this.first = first;
this.second = second;
}
sum(){
return this.first+this.second;
}
}
class PersonPlus extends Person{
constructor(name, first, second, third){
super(name, first, second);
this.third = third;
}
sum(){
return super.sum()+this.third;
}
avg(){
return (this.first+this.second+this.third)/3;
}
}
var kim = new PersonPlus("kim", 10, 20, 30);
console.log("kim.sum()", kim.sum());
console.log("kim.avg()", kim.avg());
constructor function을 통한 상속
Person class 의 내용을 prototype 을 사용해 구현
function Person(name, first, second){
this.name = name;
this.first = first;
this.second = second;
}
Person.prototype.sum = function(){
return this.first+this.second;
}
function PersonPlus(name, first, second, third){
Person.call(this, name, first, second); //다른 곳에서 정의된 함수를 현재 컨텍스트에서 실행할 수 있도록한다.
this.third = third;
}
PersonPlus.prototype.avg = function(){
return (this.first+this.second+this.third)/3;
}
var kim = new PersonPlus("kim", 10, 20, 30);
console.log("kim.sum()", kim.sum());
console.log("kim.avg()", kim.avg());
PersonPlus가 Person을 상속하기위해서 call 메소드를 사용했다.
Person의 this를 call 메소드를 통해 PersonPlus로 만들어지 지는 객체로 지정해 부모의 생성자를 호출하였다.
생성자를 통한 상속 - 부모와 연결
function Person(name, first, second){
this.name = name;
this.first = first;
this.second = second;
}
Person.prototype.sum = function(){
return this.first+this.second;
}
function PersonPlus(name, first, second, third){
Person.call(this, name, first, second);
this.third = third;
}
PersonPlus.prototype.avg = function(){
return (this.first+this.second+this.third)/3;
}
var kim = new PersonPlus("kim", 10, 20, 30);
console.log("kim.sum()", kim.sum());
console.log("kim.avg()", kim.avg());
위 코드에서 아직 Person과 PersonPlus는 아무런 연관이 없다. 따라서 PersonPlus에서 Person에 속한 sum 메소드를 호출하면 오류가 발생한다.
<현재상태>
Person과 Person's prototype, PersonPlus와 PersonPlus's prototype 객체는 서로 참조하고 있다.
PersonPlus를 통해 생성된 kim 객체는 __proto__ 는
자신을 생성한 생성자의 prototype 객체인 PersonPlus 객체의 prototype 객체를 가리키고 있다.
만약 kim에서 avg 함수를 호출하면?
kim 객체는 avg라는 프로퍼티 없으므로 kim 객체의 __proto__ 가 가리키는 PersonPlus에서 avg 라는 프로퍼티 찾아 실행한다.
kim 객체에서 sum 이라는 함수를 호출하면?
kim 객체 안에 sum 이라는 프로퍼티 없으므로 __proto__ 를 따라 PersonPlus's prototype 객체를 확인한다.
하지만 PersonPlus's prototype 객체에 sum 프로퍼티 존재하지 않아 에러가 발생한다.
따라서 PersonPlus's prototype에 찾는 프로퍼티가 없을때 Person's prototype 객체를 확인하도록 연결해줘야한다.
PersonPlus's prototype의 __proto__ 가 Person's prototype 객체를 가리키도록 한다.
<수정된 코드>
function Person(name, first, second){
this.name = name;
this.first = first;
this.second = second;
}
Person.prototype.sum = function(){
return this.first+this.second;
}
function PersonPlus(name, first, second, third){
Person.call(this, naem, first, second);
this.third = third;
}
PersonPlus.prototype.__proto__ = Person.prototype;
PersonPlus.prototype.avg = function(){
return (this.first+this.second+this.third)/3;
}
var kim = new PersonPlus("kim", 10, 20, 30);
console.log("kim.sum()", kim.sum());
console.log("kim.avg()", kim.avg());
__proto__ 는 표준이 아니므로 많은 예제에서는 Object.creat()를 사용한다.
Object.creat() 를 이용해 Person.prototype을 __proto__로 하는 새로운 객체를 생성한 후,
PersonPlus의 prototype으로 지정.
function Person(name, first, second){
this.name = name;
this.first = first;
this.second = second;
}
Person.prototype.sum = function(){
return this.first+this.second
}
function PersonPlus(name, first, second, third){
Person.call(this, name, first, second);
this.third = third;
}
PersonPlus.prototype = Object.create(Person.prototype);
PersonPlus.prototype.avg = function(){
return (this.first+this.second+this.third)/3;
}
var kim = new PersonPlus("kim", 10, 20, 30);
console.log("kim.sum()", kim.sum());
console.log("kim.avg()", kim.avg());
console.log("kim.constructor", kim.constructor);
constructor를 출력해 보면 PersonPlus가 아닌 Person으로 나온다.
constructor 속성(property)이란 무엇인가?
자바스크립트에서의 constructor 프로퍼티는 여러 의미로 사용되고, 그중 하나는
어떠한 객체가 누구로부터 만들어졌는지를 알려주는 것 이다.
Person 객체는 prototype 이라는 프로퍼티를 통해 Person's prototype 객체를 참조하고,
Person's prototype 객체는 constructor 라는 프로퍼티를 통해 Person 객체를 참조한다.
Person이라는 생성자를 통해 생성된 kim 객체에서 constructor를 호출하면 리턴되는값은??
kim에는 constructor 라는 프로퍼티가 없으므로 kim의 __proto__가 가리키는
Person's prototype 객체의 constructor가 가리키는 Person이 리턴된다.
new 키워드와 함께 constructor()를 실행하면 constructor를 몰라도 새로운 객체 생성할 수 있다.
var d = new Date();
Date.prototype.constructor === Date;
d.constructor;
d2 = new.d.constructor(); //d2 = new Date()
constructor 속성(property) 바로잡기
위 코드에서 PersonPlus로 생성된 kim 객체의 constructor가 Person으로 나오는 문제가 있다.
이유는 PersonPlus의 prototype을 Person.prototype을 __proto__로 갖는 새로운 객체를 만들어 대체 했기 때문에
이전에 PersonPlus를 constructor로 갖는 PersonPlus의 prototype이 지워졌기 때문이다.
따라서 PersonPlus.prototype의 constructor를 PersonPlus로 지정해주면 해결된다.
function Person(name,first,second){
this.name = name;
this.first = first;
this.second = second;
}
Person.prototype.sum = function(){
return this.first + this.second;
}
function PersonPlus(name, first, second, third){
Person.call(this,name,first,second);
this.third = third;
}
//PersonPlus.prototype.__proto__ = Person.prototype;
PersonPlus.prototype = Object.create(Person.prototype);
PersonPlus.prototype.constructor = PersonPlus;
PersonPlus.prototype.avg = function(){
return (this.first+this.second+this.third)/3;
}
var kim = new PersonPlus('kim', 10, 20, 30);
console.log("kim.sum()", kim.sum());
console.log("kim.avg()", kim.avg());
console.log("kim.constructor",kim.constructor);
아래 코드와 같이 변경되면 문제가 발생한다.
Object.create() 각 기존에 갖고 있던 메소드를 새로 바꾸기 때문에 avg() 메소드의 기능이 지워진다.
PersonPlus.prototype.avg = function(){
return (this.first+this.second+this.third)/3;
}
//PersonPlus.prototype.__proto__ = Person.prototype;
PersonPlus.prototype = Object.create(Person.prototype);
PersonPlus.prototype.constructor = PersonPlus;
__proto__ 는 기존의 객체를 바꾸지 않고 __proto__ 만 바꾸므로 위치에 상관 없이 사용 가능하나 비표준 방식이다.
PersonPlus.prototype.avg = function(){
return (this.first+this.second+this.third)/3;
}
PersonPlus.prototype.__proto__ = Person.prototype;
// PersonPlus.prototype = Object.create(Person.prototype);
// PersonPlus.prototype.constructor = PersonPlus;
이러한 코드를 이용하는 것보다 class 사용하는 것이 더 깔끔하고 직관적이다.
'정리' 카테고리의 다른 글
[생활코딩] WEB3 - Ajax (0) | 2021.09.14 |
---|---|
[자바스크립트의 시작] (9) Javascript 객체 고급 (0) | 2021.08.29 |
[자바스크립트의 시작] (8) Javascript 객체 기본 (0) | 2021.08.26 |
[자바스크립트의 시작] (7) Javascript 활용 (0) | 2021.08.25 |
[자바스크립트의 시작] (6) Javascript 객체 (0) | 2021.08.24 |