[aboutJS] Class 객체지향언어

Adela·2020년 8월 7일
0

aboutJS

목록 보기
5/9
post-thumbnail

참고영상: 드림코딩 | 자바스크립트 기초 강의

class나 object가 없다면?

선언한 변수들이 여기저기 동동 떠다닌다면..

규모있는 프로젝트를 만들긴.. 매우 어려웠을 듯

  • class: 좀 더 연관된 것들을 한데 묶은 container같은 아이라고 볼 수 있다.
  • 클래스를 뜯어보면 다음과 같다.

좀 더 연관있는 데이터들을 묶어놓은

  • fields
  • methods

가 종합적으로 있는 것을 클래스

※ 잠깐 알아두기

  • class: 관련있는 변수나 함수들을 묶어놓은 것
    • data class: fields만 있는 클래스
    • encapsulation: 내부적으로 보여지는 변수, 밖에서 보이는 변수를 나눠서 캡슐화
    • 상속, 다양성

객체지향 언어 라서 이것들이 이뤄짐

클래스로, 객체로 잘 만들 수 있는 개발자가 되는 것이 👍🏻

class

  • template
    • 붕어빵을 만들 수 있는 을 말함
    • 청사진, 템플릿이라고도 부름
  • declare once
    • 정의만 해놓고 한번만 선언
  • no data in
    • 메모리에 올라가지 않음

object

  • instance of a class
    • 팥붕어빵, 크림붕어빵, 초코붕어빵...
    • 만들어진 붕어빵 자체
    • 클래스를 이용해 새로운 인스턴스를 생성하면 걔가 object!
  • created many times
  • data in
    • 실제 데이터를 넣으면 메모리에 올라감

class

class 정의

ES6에 추가됨 (!!)

🖐🏻 아니 그럼.. 그 이전엔 어케 만들었는데?

  • 클래스 도입 전엔 클래스를 정의하지 않고 바로 Object를 만들었음
  • function을 통해 약간 템플릿처럼 만들어 썼음

기존에 존재하면 prototype 위에 문법만 class 추가한 것

🖐🏻 prototype..? 나중에 공부할것;

class Person{
    constructor(name, age){
      // fields
        this.name = name
        this.age = age
    }
  
  speak(){
    console.log(`${this.name}`: hello)
  }
}
  • 전달받은 name, age 데이터를 fields에 바로 전달!
  • 클래스 내 함수도 가능

object 생성

class Person{
    constructor(name, age){
      // fields
        this.name = name
        this.age = age
    }
  
  speak(){
    console.log(`${this.name}`: hello)
  }
}

const kim = new Person('yangwon', 20)
console.log(kim.name, kim.age)
kim.speak()

getter and setters

🖐🏻 이게 왜 필요한데? 왜 쓰는건데?

class User{
    constructor(firstName, lastName, age){
        this.firstName = firstName
        this.lastName = lastName
        this.age = age
    }
}

const user1 = new User('Yangwon', 'Kim', -1)
console.log(user1.age)

이러면? 나이가 -1로 출력이 된다.
-1... -1살이라는 건 말이 안된다.

즉, 누군가 데이터를 멍청하게 넣거나 이상하게 입력한다면 문제가 발생할 수 있기 때문에 getter, setter를 사용하는 것 !

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 cannot be negative')
        // }
        this._age = value < 0 ? 0 : value
    }
}

const user1 = new User('Yangwon', 'Kim', -1)
console.log(user1.age)

get age(), set age() 안에서 age를 return할 때는 _를 붙인다.

그렇지 않으면 에러가 남.. 바로 이렇게..

왜냐하면,

  • get age()를 정의하는 순간, this.age는 메모리에 있는 값을 불러오는게 아니라 getter를 호출함
  • set age()를 정의하는 순간, value로 바로 메모리의 값을 할당하는 것이 아니라, setter를 호출하게 됨
  • setter에서 전달된 value를 this.age에 할당할 때, 메모리의 값을 업데이트 하는 것이 아니라 setter를 호출하는 것 !
    • 그럼 setter로 다시 돌아옴
    • setter를 호출함
    • 그럼 setter로 다시 돌아옴
    • setter를 호출함
    • ...

이를 방지하기 위해 getter, setter안에 쓰이는 변수를 다르게 만들어주어야 함

  • 보통 _를 붙이는게 국룰인듯 ㅎ

public & private

매우 최근에 추가됨
그래서 아직 개발자들이 많이 사용하지는 않는..

class Experiment{
    publicField = 2
    #privateField = 0
}

const experiment = new Experiment()
console.log(experiment.publicField)
console.log(experiment.privateField)

privateField는 접근할 수 없음
👉🏻 그래서 undefined라고 출력된다.

static

마찬가지로 매우 최근에 추가됨

class Article{
    static publisher= 'YANGWON KIM'
    constructor(articleNumber){
        this.articleNumber = articleNumber
    }

    static printPublisher(){
        console.log(Article.publisher)
    }
}
const article1 = new Article(1)
const article2 = new Article(2)
console.log(article1.publisher)

만약 이렇게 출력문을 작성하면,

모른다고 뜬다.
지정되지 않았다고 뜬다.
왜냐하면 static은 object에 붙어있는 것이 아니라 class에 붙어있기 때문

따라서 다음과 같이 작성해주어야 한다.

class Article{
    static publisher= 'YANGWON KIM'
    constructor(articleNumber){
        this.articleNumber = articleNumber
    }

    static printPublisher(){
        console.log(Article.publisher)
    }
}

const article1 = new Article(1)
const article2 = new Article(2)
console.log(Article.publisher) // 클래스에 접근

클래스 이름을 이용해서 호출해야 한다.
(여담) 나중에 타입스크립트할때 많이 사용된다고 한다.

👉🏻 들어오는 데이터에 상관없이 클래스에서 사용할 수 있는 것이라면 static을 사용하는게 메모리사용에 더 효율적이다.

상속, 다양성

상속

class Shape{
    constructor(width, height, color){
        this.width = width
        this.height = height
        this.color = color
    }
    draw(){
        console.log(`drawing ${this.color} color of`)
    }

    getArea(){
        return this.width = this.height
    }
}

이렇게 클래스를 하나 만들었다.

헌데 만약 새로운 Rectangular라는 클래스를 만드려는데 Shape의 내용과 같은 것이 있다.

이럴 때 똑같이 복붙하지 말고 상속한다.

class Shape{
    constructor(width, height, color){
        this.width = width
        this.height = height
        this.color = color
    }
    draw(){
        console.log(`drawing ${this.color} color of`)
    }

    getArea(){
        return this.width = this.height
    }
}

class Rectangular extends Shape{
    // 이렇게만 정의해도 Shape 내 필드와 메소드 다 들어옴 
}

상속: 공통된 부분을 다른 곳에서 재사용할 수 있다

다양성

필요에 따라 상속받은 함수에서 상속을 한 함수 중 필요한 것만 따로 재정의
👉🏻 overriding이라고 함

class Shape{
    constructor(width, height, color){
        this.width = width
        this.height = height
        this.color = color
    }
    draw(){
        console.log(`drawing ${this.color} color of`)
    }

    getArea(){
        return this.width * this.height
    }
}

class Rectangular extends Shape{
    // 이렇게만 정의해도 Shape 내 필드와 메소드 다 들어옴 
}
class Triangle extends Shape{
    getArea(){
        return this.width = this.height
    }
}

const triangle = new Triangle(20, 20, 'red')
triangle.getArea()

삼각형의 넓이가 20*20 으로 나오게 된다.
헌데.. 삼각형 넓이는 이렇게 구하는게 아니쟈나 ㅜㅜ

따라서 이 부분만 따로 고쳐준다.

class Shape{
    constructor(width, height, color){
        this.width = width
        this.height = height
        this.color = color
    }
    draw(){
        console.log(`drawing ${this.color} color of`)
    }

    getArea(){
        return this.width * this.height
    }
}

class Rectangular extends Shape{
    // 이렇게만 정의해도 Shape 내 필드와 메소드 다 들어옴 
}
class Triangle extends Shape{
    getArea(){
        return (this.width * this.height)/2
    }
}

const rectangular = new Rectangular(20, 20, 'blue')
rectangular.draw()
console.log(rectangular.getArea())
const triangle = new Triangle(20, 20, 'red')
triangle.draw()
console.log(triangle.getArea())

이렇게 재정의하면, 호출된 getArea()는 더이상 Shape이 아니라 Triangle 안의 getArea()를 호출하게 됨

만약 draw()를 오버라이딩하긴 했는데.. 부모의 draw도 같이 부르고 싶다면?

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 Rectangular extends Shape{
    // 이렇게만 정의해도 Shape 내 필드와 메소드 다 들어옴 
}
class Triangle extends Shape{
    draw(){
        super.draw()
        console.log('🔺')
    }
    getArea(){
        return (this.width * this.height)/2
    }
}

const rectangular = new Rectangular(20, 20, 'blue')
rectangular.draw()
console.log(rectangular.getArea())
const triangle = new Triangle(20, 20, 'red')
triangle.draw()
console.log(triangle.getArea())

안에 super.draw()를 써준다.

부모의 메소드가 호출되고, 그 다음 Triangle 내에 정의한 메소드가 호출된다.

instanceOf

클래스를 이용해서 만들어진 새로운 인스턴스

console.log(rectangular instanceof Rectangular);
  • rectangular가 Rectangular의 인스턴스인지 아닌지
  • 클래스를 이용해 만들어진 앤지 아닌지

확인해주는 것 !

console.log(rectangular instanceof Rectangular);
console.log(triangle instanceof Rectangular);
console.log(rectangular instanceof Triangle);
console.log(triangle instanceof Shape);
console.log(triangle instanceof Object);

📌 자바스크립트에서 만든 모든 클래스, 오브젝트는 Object를 상속한다.

자바스크립트 object들

JavaScript Reference 참고

profile
개발 공부하는 심리학도

0개의 댓글