Inheritance는 OOP(객체 지향 프로그래밍)의 네가지 개념 중 상속을 말한다.
상속이란 상위 클래스의 특징을 하위 클래스에 전달하는 것을 의미한다. 하위 클래스는 상속받은 특징들과 새로운 특징을 가진다.
예를 들어, 일반 자동차의 특징을 바퀴 4개가 있고 속력을 낸다고 가정을 하자. 소방차는 기본적으로 자동차와 동일하게 바퀴 4개가 있고 속력을 낼 수 있다. 추가로 경고등이나 물을 담는 공간이 필요하다.
이처럼, 상속은 상위 클래스의 특징을 기초로 하여 새로운 특징을 추가하여 새로운 클래스를 만들때 사용한다. 이때, 당연히 상위 클래스와 하위 클래스의 타입은 동일하다.
상속하는 클래스 : 기반 클래스, 상위 클래스, 부모 클래스 라고 지징.
상속받는 클래스 : 부 클래스, 파생 클래스, 하위 클래스, 자식 클래스 라고 지칭.
자바스크립트는 프로토타입 기반 언어이다. 자바스크립트를 잘 사용하기 위해서는 프로토타입에 대해 이해를 해야하는데 그렇다면 프로토타입이란 무엇일까?
보통 다른 언어(Java, Python, Ruby, ...)에서는 클래스(Class)를 사용한다. 하지만 자바스크립에서는 클래스라는 개념이 존재하지 않고 프로토타입(Prototype)이 그 기능을 대신한다.
클래스가 없으니 당연히 상속기능도 없다. 그래서 프로토타입을 기반으로 상속기능을 비슷하게 구현하여 사용한다.
그러면 프로토타입은 어떻게 사용을 할까?
일단 기본적으로 function과 new를 사용하여 클래스처럼 사용할 수 있다.
function Animal() {//class로 사용할 땐, 대문자로 시작한다.
this.legs = 4;
this.tail = 1;
}
let dog = new Animal();
let cat = new Animal();
console.log(dog.legs) // 4
console.log(dog.tail) // 1
console.log(cat.legs) // 4
console.log(cat.tail) // 1
console.log(dog) // Animal {leg: 4, tail: 1}
console.log(cat) // Animal {leg: 4, tail: 1}
Animal.prototype // {constructor: ƒ}
dog/*
▼Animal {legs: 4, tail: 1}
legs: 4
tail: 1
▼__proto__: Object
▶constructor: ƒ Animal()
▶__proto__: Object
*/
new 키워드를 이용해서 객체를 만들었다.
그러면 이번에는 프로토타입도 사용해서 만들어보자.
/*1. Animal이라는 함수를 만든다.
2. Animal.prototype객체에 값을 추가한다.
3. Animal함수를 기반으로 dog라는 새로운 객체를 만든다.*/
function Animal() {}
Animal.prototype.legs = 4;
Animal.prototype.tail = 1;
let dog = new Animal();
console.log(dog.legs) // 4
console.log(dog.tail) // 1
dog/*
▼Animal {}
▼__proto__: Object
legs: 4
tail: 1
▶constructor: ƒ Animal()
▶__proto__: Object
*/
/*위의 결과와는 다르게 Animal이 빈 객체로 나오고
legs, tail의 값이 __proto__하위에 있다.*/
new 키워드를 사용하여 dog와 cat에 Animal의 leg, tail을 할당해주었다. Animal.prototype이라는 function을 사용하여 선언한 Object가 어딘가에 존재하고 Animal함수를 이용해 생성된 객체들이 그 Object에 있는 값을 가져다쓴다고 생각하면 된다.
Prototype에는 Prototype Link와 Prototype Object가 있다.
말그대로 객체이다. 그리고 이 객체는 언제나 함수를 사용하여 생성된다.
function Animal() { //함수
this.legs = 4;
this.tail = 1;
}
let dog = new Animal(); //함수로 새로운 객체 생성
let obj = new Object();
//Object()는 새로운 객체를 생성하는 함수이다.
함수가 실행 될 때 Constructor(생성자) 자격이 부여되어 new 키워드를 사용하여 객체를 만들 수 있게 된다. new 키워드는 컨스트럭터만 사용할 수 있는데 이 자격이 함수에만 부여되어 new 키워드는 자연스레 함수만 사용할 수 있다.
위에서 Animal.prototype이라는 function을 사용하여 선언한 Object가 어딘가에 존재한다고 했다. 이 function prototype object는 생성만 되는게 아니라 해당 함수와 연결된다.
그래서 함수는 prototype이라는 속성으로 prototype object에 접근할 수 있다. prototype object는 일반적인 객체와 같고 기본적으로 constructor와 __proto__를 속성으로 가지고 있다.
Animal.prototype
//▼{constructor: ƒ}
//▶constructor: ƒ Animal()
//▶__proto__: Object
Animal.prototype //{constructor: ƒ}
Animal.constructor //ƒ Function() { [native code] }
Animal.__proto__ //ƒ () { [native code] }
- function prototype라는 object 어딘가 생성된다. -> 여기에서 정보를 받아온다.
- 생성된 function prototype object와 연결된다.
- Constructor(생성자) 자격이 부여된다.
prototype 속성은 함수만 가지고 있지만 __proto__속성은 모든 객체가 다 가지고 있는 속성이다.
__proto__는 객체가 생성될 때 조상이었던 함수의 Prototype Object를 가리킵니다. dog는 Animal 함수를 사용하여 생성되었으니 dog의 __proto__는 Animal 함수의 Prototype Object를 의미한다.
function Animal() {}
let dog = new Animal();
dog/*
▼Animal {}
▼__proto__: Object
legs: 4
tail: 1
▶constructor: ƒ Animal()
▶__proto__: Object
*/
dog.__proto__
//{legs: 4, tail: 1, constructor: ƒ}
dog.legs //4
dog에서 legs를 검색할 때, 일단 dog객체 내에 legs의 값이 있는 지 찾는다. 하지만 dog 없기때문에 기반이 되는 상위 객체에서 찾는다. 그렇게 계속 상위로 올라가면서 최종적으로는 __proto__에 있는 값을 찾게 된다. 만약 __proto__에도 없다면 undefined를 반환한다.
이렇게 __proto__속성을 통해 상위 프로토타입과 연결되어있는 형태를 프로토타입 체인(Prototype Chain)이라고 한다.
이런 프로토타입 체인 구조 때문에 모든 객체는 최상위 Object의 자식이라고 불리고, Object Prototype Object에 있는 모든 속성을 사용할 수 있다.
Object.prototype/*
▼{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
▶constructor: ƒ Object()
▶__defineGetter__: ƒ __defineGetter__()
▶__defineSetter__: ƒ __defineSetter__()
▶hasOwnProperty: ƒ hasOwnProperty()
▶__lookupGetter__: ƒ __lookupGetter__()
▶__lookupSetter__: ƒ __lookupSetter__()
▶isPrototypeOf: ƒ isPrototypeOf()
▶propertyIsEnumerable: ƒ propertyIsEnumerable()
▶toString: ƒ toString()
▶valueOf: ƒ valueOf()
▶toLocaleString: ƒ toLocaleString()
▶get __proto__: ƒ __proto__()
▶set __proto__: ƒ __proto__()*/