20210212_JavaScript04 Class, Object, inheritance(상속), static(methods, proerties)
JavaScript04
- JavaScript에 대해 공부하기 위해서 유튜브 ‘드림코딩by엘리’ JavaScript 강의를 듣고 글을 쓰고 있다.
    
- 드림코딩by엘리 - JavaScript
        
Class vs Object
 
 - 드림코딩by엘리 - JavaScript
        
 - Class는 연관된 데이터를 묶어 정리하는 container 역할
 - Class는 fields와 methods가 종합적으로 묶여 있음
 data class: data인 fields만 들어 있는 Classincapsulation: class 안에서 내부적으로 보여지는 변수, 밖에서 보일수 있는 변수로 나누는 것inheritance- 객체로 잘 정의해서 만들수 있어야 한다.
 
// person 이라는 클래스
class person{
    name; // property - 속성(field)
    age;  // property - 속성(field)
    speak(); // function - 행동 (method)
}
Class- 붕어빵 틀
 template, declare once, no data in- 정의만 한것으로 메모리에 올라가지 않음
 
Object- 붕어빵(팥, 피자, 크림)
 instanceof a class, created many times, data in
1. Class declaration (클래스 선언)
constructor: 생성자 (like__init__in python)- constructor 생성자를 통해서 object를 만들때 필요한 데이터를 전달함
 - constructor 코드 블럭 안에 fields (this.name, this.age)에 전달하여 할당하는 것임
 - 첫 파라미터를 인스턴스 변수명으로 받지 않고 첫번째 부터 그냥 파라미터로 쓰인다. 그리고 
this를 붙여 python의self처럼 사용한다. 
this.변수명: fields 또는 property ( like인스턴스 변수in python)함수명(): method 또는 function이라고 불리고 안에서this가 붙은 인스턴스 변수를 사용할 수 있다. (like인스턴스 메소드in python)
class Person {
    //constructor 생성자
    constructor(name, age) {
        // fields
        this.name = name;
        this.age = age;
    }
    // methods
    speak() {
        console.log(`${this.name}: hello!`); // 인스턴스 메소드 인스턴스 변수 this.변수를 사용하기 때문에
    }
}
const raccoon = new Person('raccoon', 26); 
// raccoon 에 할당하여 인스턴스화 시킴
console.log(raccoon.name)
console.log(raccoon.age)
raccoon.speak(); // 인스턴스.인스턴스 함수
2. Getter and setters
- 인스턴스 및 클래스 변수 접근을 제한하기 위해서 사용
 - 사용자가 중요변수에 접근하지 못하게 하며 또한 받는 입력값에 대한 제한을 위해서 getter and setters를 사용함
 - 이것이 바로 class , method, variables(property) 를 캡슐화 시키고 접근에 대해 제한(한정?)을 걸어 커스터 마이징(private) 하는 것! = capsulation
 
class User {
    constructor(firstName, lastName, age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    get age() {
        return this._age;
    }
    set age(value) {
        // if (value < 0) {
        //     throw Error('age can not be negative')
        // }
        this._age = value < 0 ? 0 : value; 
        // value < 0 이면 0 값 아니면 value 값 할당
    }
}
const user1 = new User('Steve', 'Job', -1);
console.log(user1.age) // 사람의 나이가 -1이 불가능 -> 0으로 출력 
- 1) constructor를 통해 생성하면서 값 할당시에 setter를 호출하게 됨
 - 2) setter안에서 전달된 value를 this.age에 할당함(메모리 업데이트는 안하고)
 - 3) 값 할당 -> setter 호출 -> value -> setter 호출 -> 무한 반복 그래서 call stack이 다 찼다고 뜸
 - 4) 그래서 getter 와 setter안에서의 변수이름을 다르게 해야함
 - User 클래스에는 3개의 field 존재 firstName, lastName, _age 호출시 그냥 _age를 안쓰고 age를 사용하는 것은 _age는 내부적으로만 사용되기 때문
 
3. Fields (public, private)
- Too soon! (edge, chorme, opera 만 private 가능)
 - 생성자 constructor를 쓰지 않고 field를 정의가능 -> 
public(외부에서 접근 가능) #을 앞에 붙이면 ->private(class 내부에서만 값이 보여지고 접근 변경가능, 외부에서는 모든 접근 권한이 없음)
class Experiment {
    publicField = 2;
    #privateField = 0;
}
const experiment = new Experiment();
console.log(experiment.publicField);
console.log(experiment.privateField); // undefined 
4. Static properties and methods
- like 클래스 변수, 클래스 (멤버)메서드 in python
 - 끼리끼리 호출 조심 static있으면 클래스 변수, 메서드니까 
클래스.으로 - 인스턴스 변수, 메서드 였으면 
인스턴스.으로 호출 
class Article {
    static publisher = 'Dream Coding'; // 클래스 변수
    constructor(articleNumber) { // instance 변수 : this.articleNumber에서 articleNumber임
        this.articleNumber = articleNumber;
    }
    static printPublisher() { // 클래스 멤버 (메소드)
        console.log(Article.publisher)
    }
}
const article1 = new Article(1);
const article2 = new Article(2);
console.log(article1.publisher) // undefined
console.log(Article.publisher)  // static은 class 변수로 인식하기 때문에 클래스에서 호출해야함
Article.printPublisher(); // static이므로 class 메소드로 인식하여 클래스에서 호출
// static 사용시 메모리 절약가능 
// static 없이 method 선언시 this인 인스턴스 변수
5. Inheritance (상속)
- 중복방지를 통한 효율적 코드 사용 및 유지보수 효율
 extends를 통해서 상속 받음overriding(오버라이딩) 가능 그냥 똑같은 함수 이름 쓰면 됨- 부모 메서드 호출 `super.함수명()
 
class Shape {
    constructor(width, height, color) {
        this.width = width;
        this.height = height;
        this.color = color;
    }
    draw() {
        console.log(`drawing ${this.color} color!`);
    }
    getArea() {
        return this.width * this.height;
    }
} 
class Rectangle extends Shape {}
// overriding
class Triangle extends Shape {
    getArea() {
        return (this.width * this.height) / 2
    }
    draw() {
        super.draw() // 부모 메서드 호출
        console.log('🔺');
    }
}
const rectangle = new Rectangle(20, 20, 'blue');
rectangle.draw();
console.log(rectangle.getArea())
const triangle = new Triangle(20, 20, 'red');
triangle.draw();
console.log(triangle.getArea())
6. Class checking: instanceOf
- 좌측의 instance object가 우측의 클래스를 이용해서 만들어 졌는지 확인 -> false true값으로 return
 
console.log(rectangle instanceof Rectangle); // true
console.log(triangle instanceof Rectangle); // false
console.log(triangle instanceof Triangle); // true
console.log(triangle instanceof Shape); // true
console.log(triangle instanceof Object); // true 
// 우리가 만든 모든 클래스는 object class를 상속 받은것임
// ctrl 누르고 클릭하면 정의된 부분으로 갈 수 있음
// Object안에 선언된 함수들(내장 함수) 이름을 똑같이 overiding도 가능함 
quiz-정답
- key 값을 통하여 다른 명령을 실행할 경우 if문 보다 switch문이 훨씬 좋다.
 
function calculate1 (command, a, b) {
    switch (command) {
        case 'add':
            return a + b;
        case 'substract':
            return a - b;
        case 'divide':
            return a / b;
        case 'multiply':
            return a * b;
        case 'remainder':
            return a % b;
        default:
            throw Error('unknown command')
    }
}
console.log(calculate1('add', 2, 3))