본문 바로가기

JavaScript

20210212_JavaScript04 Class, Object, inheritance(상속), static(methods, proerties)

JavaScript04

  • JavaScript에 대해 공부하기 위해서 유튜브 '드림코딩by엘리' JavaScript 강의를 듣고 글을 쓰고 있다.(강의를 꼭보길 바란다 너무 잘되어 있다.)

Class vs Object

  • Class는 연관된 데이터를 묶어 정리하는 container 역할
  • Class는 fields와 methods가 종합적으로 묶여 있음
  • data class : data인 fields만 들어 있는 Class
  • incapsulation : class 안에서 내부적으로 보여지는 변수, 밖에서 보일수 있는 변수로 나누는 것
  • inheritance
  • 객체로 잘 정의해서 만들수 있어야 한다.
// person 이라는 클래스
class person{
    name; // property - 속성(field)
    age;  // property - 속성(field)
    speak(); // function - 행동 (method)
}
  • Class

    • 붕어빵 틀
    • template , declare once, no data in
    • 정의만 한것으로 메모리에 올라가지 않음
  • Object

    • 붕어빵(팥, 피자, 크림)
    • instance of 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))