[JavaScript] Class

soyeon·2022년 7월 8일
0
post-thumbnail

programming 패러다임

: 프로그래밍 방법론

  • 객체지향 프로그래밍
  • 함수형 -> 구조적, 절차적 프로그래밍
  • 선언적 프로그래밍

구조적(절차적) 프로그래밍

: 프로그램을 기능적으로 세분화 시키고, 기능을 모듈화 시킨다. 이때 function(함수)를 사용한다.
ex) C언어

은행 예시

예금 업무, 대출 관련 업무, 외환 관련 업무, 보험 관련 업무로 나뉘고, 각각의 업무를 또 세분화 시킨다.

구조적(절차적) 프로그래밍의 장점

  • 프로그램을 쉽고, 빠르게 구현할 수 있다.
  • 설계가 비교적 간단하다.

구조적(절차적) 프로그래밍의 단점

  • 유지보수가 힘들다.
    => 유지보수를 잘하기 위해 객체지향 개념이 생기고, 그 방식으로 프로그래밍을 할 수 있는 프로그램 언어들이 등장했다.

객체지향 프로그래밍

: "유지보수성"

  • 프로그램을 기능으로 세분화하지 않는다.
  • 현실 세계에 있는 내가 해결해야 하는 문제를 program적으로 표현하기 위해 노력한다. -> Modeling
  • 문제를 구성하는 구성요소를 파악하고, 그 구성요소 간에 어떤 data가 오고 가는지를 파악해서 프로그램으로 묘사한다.
  • 상태와 행위로 구분한다.

ex) JAVA(객체 지향 개념을 가장 잘 대변하고 있는 프로그래밍 언어), C++, ...

은행 예시

  • 고객에게는 여러 상태와 행위들이 존재한다. 여기에서 은행에 필요한 상태와 행위만 뽑아낸다. -> Abstraction(추상화)
  • 상태는 변수행위는 함수로 표현한다.

=> Class 를 이용한 객체 Modeling

Class

: 현실세계에 존재하는 객체를 모델링하는 수단
: instance를 만들어내는 수단
: 새로운 데이터 타입을 만들어내는 수단 - ADT(Abstract Data Type)

Interitance (상속)

상속의 가장 큰 목적 : 코드의 재활용

위에 있는 클래스 : super class, parent class, upper class, base class
아래에 있는 클래스 : sub class, child class, derived class

두개의 클래스가 상속 관계에 있다는 것을 is-A relationship 이라고 부른다.
=> sub class is a super class -> 성립
=> super class is a sub class -> 성립 X

is-A relationship으로 Polymorphism(다형성)이 등장하였다.

JavaScript Class

"문법적 설탕"

JavaScript는 prototype 기반의 객체지향(객체기반) 언어로 Class가 필요없다. 하지만 사람들의 편리를 위해 ES6부터는 Class를 도입했다.

JavaScript Class 특징

  • 생성자 함수와 유사하다.
    => Class 자체가 함수이면서 객체인 것이다.
    => instance를 생성할 수 있다.

  • 생성자 함수와 다르게 반드시 "new" keyword가 필요하다.
    : class 이름이 아니라 식별자를 사용한다. instance가 실제로 만들어지는 함수는 constructor이다. this keyword와 binding까지 하고 끝나면 묵시적으로 this를 return한다.

class Person {
    constructor(name) {
        this.name = name;
    }
}

const me = new Person('홍길동');
  • Class간의 상속을 지원한다.
    => "extends", "super" keyword를 사용한다.

  • Class 역시 hoisting이 발생한다.
    => let, const처럼 hoisting이 된다.

const Person = '안녕하세요';

{
    console.log(Person);

    class Person {
        
    }
}

실행 결과 : ReferenceError: Cannot access 'Person' before initialization
  • Class 내부코드는 string mode로 동작한다.

  • Class 안에는 constructor, prototype 메소드, static 메소드가 있다.
    => 이 property의 property attribute 값은 모두 false이다.

Class 만들기

// class define
class Person {

}

// 익명 class 표현식
const Person1 = class {};

// 기명 class 표현식
const Person2 = class MyClass {};

Class는 0개 이상의 method로 구성

: class는 0개 이상의 method로 구성된다. method는 ES6 축약표현으로 된 method만 나올 수 있다.

method 종류

  1. constructor method(생성자)
    : 인스턴스의 초기화를 담당한다.
    - 1개만 존재할 수 있다.
    - 생략할 수 있다. 생략한 경우 JavaScript engine에 의해 인자가 없고, 하는 일이 없는 constructor가 자동으로 삽입된다.
    - return 구문은 사용하지 않는다. 묵시적으로 this를 리턴한다.
  2. prototype method
  3. static method
class Person {
    // constructor(생성자)
    constructor(name) {
        // instance의 초기화
        // instance의 property를 설정한다.
        this.name = name;
    }

    // prototype method
    // instance가 실제로 상속해서 사용할 수 있다.
    sayHello() {
        console.log('안녕하세요');
    }

    // static method
    static sayHi() {
        console.log('이건 static');
    }    
}

const me = new Person('홍길동');

접근자 property

: property임에도 불구하고 [[Value]]를 가지고 있지 않다. 일반적으로 다른 property의 값을 읽어오거나(getter) 저장할 때(setter) 사용한다.

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    get fullName() {
        return `${this.lastName}${this.firstName}`;
    }

    set fullName(name) {
        [this.lastName, this.firstName] = name.split(' ')
    }
};

const me = new Person('길동', '홍');
me.fullName = '김 연아';
console.log(me.fullName);

실행 결과 : 김연아

객체 literal에서 접근자 property 사용해보기

// 객체 literal을 이용해서 객체 생성
const Person = {
    firstName: '길동',
    lastName: '홍',

    // get을 이용하면 반드시 return 구문이 존재해야 한다.
    get fullName() {
        return `${this.lastName}${this.firstName}`;
    },

    set fullName(name) {
      	// 유효성 검사를 할 수 있다.
        [this.lastName, this.firstName] = name.split(' ')
    }
};

Person.fullName = '김 연아';
console.log(Person.fullName);

실행 결과 : 김연아

상속에 따른 class 확장

: class의 상속은 extends를 사용한다. prototype 기본 상속과는 다르다
하위 class의 [[Prototype]]나 __proto__에 이어져있는 것이 상위 class이다.

// 상위 class(super class)
class foo {}

// 하위 class(sub class)
class bar extends foo {}


const obj = new bar();

위의 코드에 대한 그림 설명

  • sub class bar는 super class foo의 상속을 받는다

  • sub class bar의 [[Prototype]]은 super class foo를 가리킨다.
    -> class 기반의 상속

  • super class foo의 [[Prototype]]은 Function의 prototype 객체를 가리킨다.

  • bar의 prototype 객체의 [[Prototype]]은 foo의 prototype 객체를 가리킨다.
    -> prototype 기반의 상속

  • bar의 instance obj의 [[Prototype]]은 bar의 prototype 객체를 가리킨다.
    -> prototype 기반의 상속

  • foo의 prototype 객체의 [[Prototype]]은 Object의 prototype 객체를 가리킨다.

  • Function의 prototype 객체의 [[Prototype]]은 Object의 prototype 객체를 가리킨다.

상속 예제 1

// super class
class Animal {
    constructor(age, weight) {
        this.age = age;
        this.weight = weight;
    }

    eat() {
        return '밥을 먹어요!';
    }

    move() {
        return '움직여요';
    }
    
}

class Bird extends Animal {
    constructor(age, weight, kk) {
        // 상위 클래스의 constructor를 호출
        super(age, weight);  // super()보다 this.kk = kk를 먼저 실행할 수 없다.
        this.kk = kk
    }

    fly() {
        return '날아요!';
    }

}

const bird = new Bird(10, 30, 100);

console.log(bird);
console.log(bird instanceof Bird);  // bird가 뒤쪽 class의 instance인지 확인한다.
console.log(bird instanceof Animal);

상속 예제 2

class Base {
    constructor(name) {
        this.name = name;
    }

    sayHello() {
        return '안녕하세요!';
    }
}

class Derived extends Base {
    sayHello() {
        return super.sayHello() + this.name;
    }
}

const derived = new Derived('홍길동');
console.log(derived.sayHello());

class간 상속 & 생성자 함수간 상속

: class간 상속은 가능하지만 생성자 함수간 상속은 불가능하다. class와 생성자 함수는 상속 관계를 가질 수 있다.
=> class는 생성자 함수로부터 상속을 받을 수 있다.

function Base(name) {
    this.name = name;
}

class Derived extends Base {}

동적 상속
: extends 키워드 뒤에 값으로 평가될 수 있는 식이 올 수 있다.
JavaScript 특유의 형태이다.

function Base1(name) {
    this.name = name;
}

class Base2 {

}

let tmp = true;

// 3항 연산자 ( ? ... : ... )
class Derived extends (tmp ? Base1 : Base2) {
  
}

0개의 댓글