[JS] 7.1. 상속
작성:    
업데이트:
카테고리: JS boostcourse
태그: FE Language, JS, JS boostcourse
참고 자료
상속(Inheritance)
- class에 필요한 메서드가 있는데 추가할 수 없는 경우(다른 사람의 코드, 라이브러리 등)
-
class 자체에 추가하면서 무겁게 되길 원치 않는 경우
- 모든 요소를 받을 클래스를
extends class명
을 통해서 부모 클래스로 두고 상속
class Person {
constructor(name, first, second) {
this.name = name;
this.first = first;
this.second = second;
}
sum() {
return "class method > " + this.name + " : " + (this.first + this.second);
}
}
class PersonPlus extends Person {
avg() {
return (this.first + this.second) / 2;
}
}
var kim = new PersonPlus("kim", 10, 20);
console.log("kim.sum()", kim.sum());
console.log("kim.avg()", kim.avg());
- avg() 메서드를 Person 클래스 자체에 넣지 않고, Person 클래스를 부모 클래스로 하여 상속받는 PersonPlus 클래스에 메서드를 새로 만들었다.
- 부모 클래스의 요소인 name, first, second 등을 모두 받아온다.
- 부모 클래스의 메서드도 사용 가능하고 자식 클래스의 메서드도 사용 가능하다.
- 부모 클래스에 이미 있는 메서드가 마음에 들지 않는다면 자식 클래스에서 바꾸어도 된다.
super
- 부모 클래스의 요소를 불러 가져오고, 부모 클래스에서 하지 못하는 것들을 자식에서 할 수 있도록 하는 것
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 (super.sum() + this.third) / 3;
}
}
var kim = new PersonPlus("kim", 10, 20, 30);
console.log("kim.sum()", kim.sum());
console.log("kim.avg()", kim.avg());
super(param1, param2,...)
: 부모 클래스의 생성자 호출, 자식 클래스에 super()로 가져올 수 있다.- 생성자 vs 생성자 이므로 자식 생성자 이전에 부모 생성자를 가져올 수 있다.
super.~~~
: 부모 클래스의 메서드 호출- super을 이용해 간단하게 상속 클래스에서 수정 가능
Object Inheritance
- 일반적인 프로그래밍 언어에서 상속은 클래스끼리만 되고 인스턴스끼리는 상속이 되지 않는다.
- 자바스크립트는 너무 유연한 언어라 super object로부터 sub object가 기능을 상속받을 수 있다.
- 심지어 super object를 상속하고 있다가 다른 객체에게 상속받을 필요가 있다면
prototype link
만 다른 객체로 바꿔주면 된다. - 이 prototype link는 별도의 지정이 없으면 super object와 연결되어 있는 것.
- super와 상관 없이
prototype link
로 연결되어 있는 객체를prototype object
라고 부른다.
__proto__
- class를 사용하지 않고
__proto__
를 사용해 상속한다. - 클래스와 클래스가 아닌, 객체가 객체를 상속하도록 하는 것이다.
var superObj = { superVal: "super" };
var subObj = { subVal: "sub" };
subObj.__proto__ = superObj;
console.log("subObj.subVal =>", subObj.subVal);
console.log("subObj.superVal =>", subObj.superVal);
// subObj.subVal => sub
// subObj.superVal => super
- subObj에는 없는 superVal key를 이용해 super를 출력한다.
subObj.__proto__ = superObj;
를 통해 인스턴스 상속을 한 것!- 우선 subObj에 superVal을 찾아보고 인스턴스 내에 이게 없으면
__proto__
연결한 인스턴스에 있는지 확인
subObj.superVal = "sub";
console.log("superObj.superVal =>", superObj.superVal);
// superObj.superVal => super
- subObj의 superVal 프로퍼티를 바꾸더라도, 객체의 proto의 프로퍼티가 바뀌지는 않는다.
prototype
- constructor 안이 아닌 밖에서 Method를 지정할 수 있다.
- 모든 객체들이 프로토타입을 함께 쓸 수 있게 한다.
__proto__
: 객체가 객체를 상속하도록 한다.
Object.create()
- 객체가 객체를 상속받기 위해서 위에서는
__proto__
를 사용하였다.
// __proto__ 사용
var superObj = { superVal: "super" };
var subObj = { subVal: "sub" };
subObj.__proto__ = superObj;
그런데 Object.create()
를 이용해 부모 객체로부터 자식 객체를 만들 수 있다.
// Object.create() 사용
var superObj = { superVal: "super" };
var subObj = Object.create(superObj);
subObj.subcal = "sub";
call
- 모든 함수는 call이라는 메서드를 가진다.
- 모든 함수는 객체이기 때문
- 객체와 연결해 객체의 속성을 이용해 함수 동작을 할 수 있다. (this가 객체가 됨)
- 일시적으로 객체를 연결해 함수를 호출할 때 객체의 속성을 사용한다.
var kim = {
name: "kim",
first: 10,
second: 20,
};
var lee = {
name: "lee",
first: 10,
second: 10,
};
// 어느 객체에 속하지 않고 외부에 있는 함수
function sum() {
return this.first + this.second;
}
// sum이라고 하는 객체를 실행한다는 의미( = sum(); )
sum.call(kim);
이렇게 call() 내부에 인자로 kim을 주게 되면, this는 kim
이 되는 것이다.
call의 사용
// sum이라고 하는 객체를 실행한다는 의미( = sum(); )
console.log("sum.call(kim)", sum.call(kim));
console.log("sum.call(lee)", sum.call(lee));
// sum.call(kim) 30
// sum.call(lee) 20
parameter가 있는 경우
sum() 함수가 sum(prefix)처럼 인자를 가지고 어떤 객체의 프로퍼티를 사용한다고 가정해보자.
function sum(prefix) {
return prefix + (this.first + this.second);
}
// sum이라고 하는 객체를 실행한다는 의미( = sum(); )
console.log("sum.call(kim)", sum.call(kim, " => "));
console.log("sum.call(lee)", sum.call(lee, " : "));
// sum.call(kim) => 30
// sum.call(lee) : 20
위에처럼 함수가 어떤 객체를 참조하는지 먼저 괄호에 쓰고, 뒤에 parameter를 추가한다.
bind
- call()은 함수에 사용할 객체를 매번 지정해줘야 한다.
- bind()는 함수가 인자를 참조하여 this로 고정하는 새로운 함수를 만드는 것
// 내부적으로 this를 kim으로 하는 새로운 함수 생성
var kimSum = sum.bind(kim, "-> ");
console.log("kimSum()", kimSum());
// kimSum() -> 30
kimSum()
은 sum의 this를 kim으로 영구적으로 고정한 아예 새로운 함수이다.
prototype vs __proto__
- 함수는 객체여서 메서드를 가질 수 있다.
- 함수 객체가 만들어지면 prototype 객체도 같이 만들어진다.
- 함수 객체와 prototype 객체는 연관이 되어있다.
- 함수의 prototype 프로퍼티는 prototype 객체를 가리킴
- prototype 객체의 constructor 프로퍼티는 함수 객체를 가리킴
- 즉 서로 상호참조를 하고 있는 관계
function Person(name, first, second) {
this.name = name;
this.first = first;
this.second = second;
}
// Person 함수 객체의 프로토타입 객체에 sum 함수를 생성 및 정의
Person.prototype.sum = function () {};
// 객체 kim 생성
var kim = new Person("kim", 10, 20);
- 객체 kim을 생성하면 parameter로 전달해준 값이 내부에서 정의됨
__proto__
프로퍼티가 kim 객체 내부에 생김- 이는 인스턴스를 만든 클래스의 prototype 프로퍼티를 가리킨다.
-
결국 Person’s prototype 객체를 가리키는 것
-
인스턴스 외부에서 인스턴스의 프로퍼티를 검색(kim.name)할 때
- 인스턴스 내부에 해당 프로퍼티가 있으면 반환
- 없으면
__proto__
가 가리키는, 즉 Person’s prototype 객체 내에 있는지 확인
- kim.sum()은 kim 인스턴스 내에 없다.
__proto__
인 Person’s prototype 객체의 sum() 메서드를 불러온다.
번외: debugger
- JS 코드에
debugger;
를 입력하고 브라우저에 렌더링하면, 해당 부분까지 코드를 진행한 뒤 일시정지된다. - 크롬 브라우저의 개발자도구에서 객체의 상태를 자세히 확인할 수 있다.
- [Sources - Watch]에 객체명을 검색해 상세 내용을 확인하면 된다.
댓글남기기