Class 상속 – 생성자 함수
- 이전 글에서 공부한 Prototypal Inheritance 개념을 개발자가 생성한 클래스 간에 생성해주려면 어떻게 해야할까?
const Person = function (firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
};
Person.prototype.calcAge = function () {
console.log(2037 - this.birthYear);
};
const Student = function (firstName, birthYear, course) {
Person.call(this, firstName, birthYear);
this.course = course;
};
// Linking prototypes
Student.prototype = Object.create(Person.prototype);
Student.prototype.introduce = function () {
console.log(`My name is ${this.firstName} and I study ${this.course}`);
};
Object.create
로 Person과 Student 링크해준다.
- 자식 프로토타입 내부에서는
call
메소드를 호출해서 부모 프로토타입의 프로퍼티를 초기화해준다.
console.log(mike instanceof Student); // true
console.log(mike instanceof Person); // true
console.log(mike instanceof Object); // true
console.log(mike.__proto__); // Person(prototype which contains introduce function) -> bug
console.log(mike.__proto__.__proto__); // prototype which contains calcAge function
Student.prototype.constructor = Student;
console.dir(Student.prototype.constructor); // Student
Object.create
로 링크해준 경우 mike.__proto__가 Person으로 나오게 되는데, 이 경우 constructor를 Student로 정정해줄 수 있다.
Class 상속 – ES6 Classes
class PersonCl {
constructor(fullName, birthYear) {
this.fullName = fullName;
this.birthYear = birthYear;
}
// Instance methods
calcAge() {
console.log(2037 - this.birthYear);
}
greet() {
console.log(`Hey ${this.fullName}`);
}
get age() {
return 2037 - this.birthYear;
}
set fullName(name) {
if (name.includes(' ')) this._fullName = name;
else alert(`${name} is not a full name!`);
}
get fullName() {
return this._fullName;
}
// Static method
static hey() {
console.log('Hey there 👋');
}
}
class StudentCl extends PersonCl {
constructor(fullName, birthYear, course) {
// Always needs to happen first!
super(fullName, birthYear);
this.course = course;
}
introduce() {
console.log(`My name is ${this.fullName} and I study ${this.course}`);
}
calcAge() {
console.log(
`I'm ${
2037 - this.birthYear
} years old, but as a student I feel more like ${
2037 - this.birthYear + 10
}`
);
}
}
- ES6 클래스의 경우 extends 키워드와 super를 사용해서 링크해줄 수 있다.
Class 상속 – Object.create
const PersonProto = {
calcAge() {
console.log(2037 - this.birthYear);
},
init(firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
},
};
const steven = Object.create(PersonProto);
const StudentProto = Object.create(PersonProto);
StudentProto.init = function (firstName, birthYear, course) {
PersonProto.init.call(this, firstName, birthYear);
this.course = course;
};
StudentProto.introduce = function () {
console.log(`My name is ${this.firstName} and I study ${this.course}`);
};
const jay = Object.create(StudentProto);
jay.init('Jay', 2010, 'Computer Science');
jay.introduce();
jay.calcAge();
PersonProto
를 상속하는 StudentProto
를 Object.create
로 연결해준 후 부모의 프로퍼티와 자식의 프로퍼티를 초기화해 줄 init
메소드를 생성해준다.
캡슐화 – protected, private
// Encapsulation: Protected Properties and Methods
// Encapsulation: Private Class Fields and Methods
// 1) Public fields
// 2) Private fields
// 3) Public methods
// 4) Private methods
// (there is also the static version)
class Account {
// 1) Public fields (instances)
locale = navigator.language;
// 2) Private fields (instances)
#movements = [];
#pin;
constructor(owner, currency, pin) {
this.owner = owner;
this.currency = currency;
this.#pin = pin;
// Protected property
// this._movements = [];
// this.locale = navigator.language;
console.log(`Thanks for opening an account, ${owner}`);
}
// 3) Public methods
// Public interface
getMovements() {
return this.#movements;
}
deposit(val) {
this.#movements.push(val);
return this;
}
withdraw(val) {
this.deposit(-val);
return this;
}
requestLoan(val) {
// if (this.#approveLoan(val)) {
if (this._approveLoan(val)) {
this.deposit(val);
console.log(`Loan approved`);
return this;
}
}
static helper() {
console.log('Helper');
}
// 4) Private methods
// #approveLoan(val) {
_approveLoan(val) {
return true;
}
}
- protected 프로퍼티나 메소드를 작성하려면
_
키워드를 사용하면 된다. 해당 키워드가 사용된 경우 인스턴스 단에서 사용하지 않도록 암묵적인 약속을 한것과 같으나, 실제로 호출은 가능하다.
- 아예 호출이 불가능한 private 프로퍼티나 메소드를 작성하려면
#
키워드를 사용하면 된다.
- Uncaught SyntaxError가 발생한다.
const acc1 = new Account('Jonas', 'EUR', 1111);
// acc1._movements.push(250);
// acc1._movements.push(-140);
// acc1.approveLoan(1000);
acc1.deposit(250);
acc1.withdraw(140);
acc1.requestLoan(1000);
console.log(acc1.getMovements());
console.log(acc1);
Account.helper();
// console.log(acc1.#movements);
// console.log(acc1.#pin);
// console.log(acc1.#approveLoan(100));
메소드 체이닝
// Chaining
acc1.deposit(300).deposit(500).withdraw(35).requestLoan(25000).withdraw(4000);
console.log(acc1.getMovements());
- 클래스의 메소드도 체이닝해서 사용할 수 있다.
Related