Make Inheritance

custom으로 만든 class혹은 function끼리의 Inheritance 관계를 만드는 방법과 Encapsulation을 하는 방법과 관련 이론들

예시로 Person을 parent로 Student를 child로 둔다.

Constructor functions

전통적으로 function으로 object를 만드는 방법

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){
    //Student로 만들어진 new object = this
    //call에 의해 해당 object에 Person의 Property들이 함께한다.
    Person.call(this, firstName, birthYear);

    //이건 일반 function을 부를때 사용하는 방법이다. 따라서 Error(firstName이 정의되어 있지 않으니)
    //Person(firstName, birthYear);

    //parent에 추가된 property
    this.course = course;
}

//aka. linking prototypes
//이것으로 Student.prototype은 Person.prototype을 직접 바라보게 되었다.(자체 property들은 초기화)
//주의!! Person.prototype의 constructor는 Person이기 때문에 Student로 바꾸어 주어야 한다.
Student.prototype = Object.create(Person.prototype);

//Constuctor 수정
//Student의 prototype object의 constructor가 Person이 아닌 Student를 바라보게 올바르게 수정하였다!
Student.prototype.constructor = Student

/*
    Object.create순서
    - 만약 Object.create를 custom 후에 선언하면 Student.prototype은 빈 object로 overwrite되어버린다.
    - 따라서! Object.create를 한 후에 Student.prototype에 property들을 추가해야한다.
*/
Student.prototype.introduce = function(){
    console.log('My name is ${this.firstName} and I study ${this.course}');
}

const mike = new Student('mike', 2020, 'computer science');
mike.introduce();               //My name is mike and I study computer science

call method에 대한 자세한 설명

[https://webclub.tistory.com/394]

[https://velog.io/@rohkorea86/this-%EC%99%80-callapplybind-%ED%95%A8%EC%88%98-mfjpvb9yap]

잘못된 예시

아래처럼 설정하면 Student도 Person의 Prototype object를 바라보기 때문에 new하면 Person의 Object가 만들어진다.

Student.prototype = Person.prototype;

ES6 Classes

ES6에 추가된 class syntax로 object를 만드는 방법

주목할 점은 class의 간단한 extends방법으로

  • instance의 prototype을 부모 prototype object로 알아서 설정
  • 어긋날 수 있는 constructor를 올바르게 만들어진 class의 constructor를 바라보게 함

을 알아서 해준다는 점이다. (전통적인 방법에선 수동으로 수정해주어야 했다.)

class PersonCl{
    constructor(firstName, birthYear){
        this.firstName = firstName;
        this.birthYear = birthYear;
    }

    calcAge(){
        console.log(2037 - this.birthYear);
    }
}

class StudentCl extends PersonCl{
    constructor(firstName, birthYear, course){
        //super는 반드시 가장 먼저 나와야한다.
        //이유 : super를 통해 subclass와 연동하여 this를 올바르게 설정해주기 때문이다.
        super(firstName, birthYear);
        this.course = course;
    }

    introduce(){
        console.log('My name is ${this.firstName} and I study ${this.course}');
    }

    //Overrride
    calcAge(){
        console.log('I born in ${this.birthYear}');
    }
}

const martha = new StudentCl('martha', '2012', 'Computer Science');
martha.introduce();         //'My name is martha and I study Computer Science
martha.calcAge();           //I born in 2012

Object.create

new 와의 특징은 constructor의 걱정을 할 필요가 없다는 것.

object와 object를 그대로 잇는 것이기 때문

const PersonProto = {
    calcAge(){
        console.log(2037 - this.birthYear);
    },

    init(firstName, birthYear){
        this.firstName = firstName;
        this.birthYear = birthYear;
    },
};

const steven = Object.create(PersonProto);

//자신의 property가 하나도 없는 object와 그 prototype을 PersonProto로 가진 object생성
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}');
}

//자신의 property가 하나도 없는 object와 그 prototype을 StudentProto로 가진 object생성
const jay = Object.create(StudentProto);
jay.init('Jay', 2010, 'Computer Science');
jay.introduce();                                //My name is Jay and I study Computer Science

Encapsulation

Javascript는 Java나 c언어처럼 언어 레벨에서 private를 지원하진 않는다.

하지만 convention을 통해 가짜로 private를 만들어 낼 수 있다.

Protected

앞에 ‘_‘를 붙여서 function안에서만 사용하는 property 혹은 method라는 것을 알린다.

Private

현재 private 기능을 개발 진행중이며 완벽하지는 않지만 Google Chrome에서는 지원하고 있다.

개발 진행중이니 눈여겨 보아야한다.

class Account{
    
    //변수명 앞에 #을 붙여주면 private이 된다.
    //private field는 반드시 전역변수로 따로 설정해주어야 클래스 내에서 사용할 수 있다.
    #movement = [];
    #pin;

    constructor(owner, currency, pin){
        this.owner = owner;
        this.currency = currency;
        this.#pin = pin;
    }

    //method도 마찬가지
    //하지만 method가 아닌 field취급을 한다 = 미완성
    #approveLoan(){
        return true;
    }
}

const account = new Account('jim', 2323000, 12313);
console.log(account.#movement);         //error
console.log(account.#approveLoan())     //error

chaining methods

여러 method를 한번에 이어서 사용하는 방법

class Account{
    
    #movement = [];
    #pin;

    constructor(owner, currency, pin){
        this.owner = owner;
        this.currency = currency;
        this.#pin = pin;
    }

    deposit(val){
        movement.push(val);
        //return없이는 undefined를 return하기 때문에 자신을 반환하면 다시 자신 안의 method를 사용할 수 있으므로 chining이 가능하다.
        return this;
    }
    withdrawal(val){
        movement.push(-val);
        //이런식으로 특별한 return이 없는 method에 자신을 반환해 method chaining이 가능하도록 할 수 있다.
        return this;
    }
}

const accout = new Account('hey', 20000000, 1221);
account.deposit(123).deposit(346).withdrawal(10);