class Car {
constructor(make, model) {
this.make = make;
this.model = model;
this.userGears = ["P", "N", "R", "D"];
this.userGear = this.userGears[0];
}
shift(gear) {
if (this.userGears.indexOf(gear) < 0)
throw new Error(`Invalid gear: ${gear}`);
this.userGear = gear;
}
}
const carA = new Car("Kia", "Morning");
const carB = new Car("Tesla", "Model S");
car1.shift("D");
car2.shift("R");
프로토타입
클래스의 인스턴스에서 사용할 수 있는 메소드는 프로토타입(prototype) 메소드를 가리킨다. 예를 들어 이전 포스트에서 작성했던 위의 코드, Car의 인스턴스에서 사용할 수 있는 shift 메소드는 프로토타입 메소드인 것이다. 프로토타입 메소드는 Car.prototype.shift로 표기하는 경우가 많다. Array의 forEach를 Array.prototype.forEach라고 쓰는 것과 동일하다.
(여기서 유추하는 점은 그럼 Array도 하나의 클래스 혹은 인스턴스로 볼 수 있다는 것인가?)
모든 함수에는 prototype이라는 특별한 프로퍼티가 있다.
콘솔 창에서 이 객체를 본적이 있을 것이다. 일반적인 함수에서는 프로토타입을 사용할 일이 없지만, 객체 생성자로 동작하는 함수에서는 프로토타입을 사용하는 일이 매우 중요해진다. 함수의 prototype이 중요해지는 시점은 new 키워드로 새 인스턴스를 만들었을 때인데, new 키워드로 만든 새 객체가 생성자(constructor)의 prototype 프로퍼티에 접근할 수 있게 되기 때문이다.
객체 인스턴스는 constructor의 prototype 프로퍼티를 __proto__ 프로퍼티에 저장한다. 프로토타입에서 가장 중요한 것은 동적 디스패치라는 메커니증민데, 여기서 디스패치는 메소드 호출과 같은 의미이다. 객체의 프로퍼티나 메소드에 접근하려 할 때 그런 프로퍼티가 존재하지 않으면 자바스크립트는 객체의 프로퍼티에서 해당 프로퍼티나 메소드를 찾는다. 클래스의 인스턴스는 모두 같은 프로토타입을 공유한다. 따라서 프로토타입에 프로퍼티나 메소드가 있다면 해당 클래스의 인스턴스는 모두 그 프로퍼티나 메소드에 접근할 수 있다.
상속
위의 프로토타입을 정리하면서, 상속의 부분을 확인할 수 있었다. 클래스의 인스턴스는 클래스의 기능을 모두 상속한다. 상속은 한 단계로 끝나지 않는다. 객체의 프로토타입에서 메소드를 찾지 못하면 자바스크립트는 프로토타입의 프로토타입을 검색한다. 프로토타입 체인이 이런 방법으로 만들어지는 것이다. 자바스크립트는 조건에 맞는 프로토타입을 찾을 때까지 프로토타입 체인을 계속 거슬러 올라가고, 조건에 맞는 프로토타입을 찾지 못하면 에러를 일으킨다.
프로토타입 체인을 염두에 두면 클래스의 계층 구조를 효율적으로 만들 수 있다. 즉, 프로토타입 체인에서 가장 적절한 위치에 메소드를 정의해주는 것이다.
class Vehicle {
constructor() {
this.passengers = [];
console.log("Vehicle created");
}
addPassenger(p) {
this.passengers.push(p);
}
}
class Car extends Vehicle {
constructor() {
super();
console.log("Car created");
}
deployAirbags() {
console.log("It's SAFE!!!");
}
}
위의 코드를 통해 적절한 위치에 메소드를 작성하는 것이 효율적이라는 것을 알 수 있다. 운송 수단은 대부분 승객을 태울 수 있다. 그렇기에 addPassenger라는 메소드를 운송 수단 클래스에 넣어준 것이고, 그 subclass인 자동차에는 자동차에서만 나오는 에어백 기능을 추가해준 것 위의 코드에서 extends라는 키워드는 Car 키워드를 서브 클래스로 만들어준 것이다. super()라는 함수는 슈퍼클래스의 생성자를 호출하는 함수이다. 중요한 점은 super() 함수를 꼭 우선으로 호출해야 한다. 그렇지 않으면 에러가 일어난다!
const v = new Vehicle();
v.addPassenger("John");
v.addPassenger("Sam");
console.log(v.passengers);
const c = new Car();
c.addPassenger("Ming");
c.addPassenger("Nim");
console.log(c.passengers);
console.log(v.deployAirbags);
console.log(c.deployAirbags);
c에서는 deployAirbags를 호출할 수 있지만, v에서는 불가능하다. 상속은 단방향으로 이뤄지기 때문이다. Car 클래스의 인스턴스는 Vehicle 클래스의 모든 메소드에 접근할 수 있지만, 반대는 불가능하다.
'개발 R.I.P.' 카테고리의 다른 글
7.27 Dev.Feedback ( forEach) (0) | 2021.07.27 |
---|---|
7.26 Dev.Feedback ( 검색 알고리즘 선형검색, 이진검색) (0) | 2021.07.26 |
7.19 Dev.Feedback ( 객체지향 프로그래밍 ) (0) | 2021.07.19 |
7.17 Dev.Feedback (API, POSTMAN) (0) | 2021.07.17 |
7.16 Dev.Feedback ( 비동기적 프로그래밍 # B Fetch, Async) (0) | 2021.07.16 |