loading
본문 바로가기
Language/JavaScript

[JS] 10. 클래스

by NeuLyeo 2024. 10. 22.

[JS] 10. 클래스

 

 

 

 

📚 Table of Contents

     

     

     

     

    01. prototype

    프로토타입(prototype)은 자바스크립트의 객체 지향 프로그래밍의 핵심 개념입니다.
    이는 객체들 사이에서 속성과 메서드를 공유하는 메커니즘을 제공합니다.

     

    주요 특징:

    1. 상속 : 객체는 프로토타입으로부터 속성과 메서드를 상속받습니다.
    2. 메모리 효율성 : 여러 객체가 동일한 프로토타입을 공유하여 메모리를 절약합니다.
    3. 동적 수정 : 프로토타입은 런타임에 수정할 수 있어 유연성을 제공합니다.

    프로토타입 체인:
    객체의 프로퍼티나 메서드를 찾을 때, 자바스크립트 엔진은 해당 객체에서 시작하여 프로토타입 체인을 따라 올라가며 검색합니다.


     

    prototype 속성을 통해 새로운 메서드를 추가할 수 있습니다. 이를 통해 모든 인스턴스가 공유할 수 있는 공통 메서드를 정의할 수 있습니다.

     

    예를 들어, 배열의 prototype에 새로운 메서드를 추가하면 모든 배열 인스턴스에서 해당 메서드를 사용할 수 있습니다.

     // const fruits = ['Apple', 'Banana', 'Cherry'] 리터럴 방식
    const fruits = new Array('Apple', 'Banana', 'Cherry') // 생성자 함수
    
    console.log(fruits) // ['Apple', 'Banana', 'Cherry']
    console.log(fruits.length) // 3
    console.log(fruits.includes('Apple')) // True
    console.log(fruits.includes('Orange')) // False
    
    // Array.prototype에 새로운 메서드 'ex'를 추가합니다.
    Array.prototype.ex = function () {
      console.log(this) // 이 메서드는 배열 자체를 로그로 출력합니다.
    }
    
    // 'fruits' 배열에 'ex' 메서드를 호출합니다.
    fruits.ex() // ['Apple', 'Banana', 'Cherry']
    
    // 새로운 빈 배열 'arr'를 생성합니다.
    const arr = []
    // 'arr' 배열에 'ex' 메서드를 호출합니다.
    arr.ex() // []

     

    function User(first, last) {
      this.firstName = first
      this.lastName = last
    }
    
    // User.prototype에 getFullName 메서드를 추가합니다.
    User.prototype.getFullName = function () {
      return `${this.firstName} ${this.lastName}`
    }
    
    // User 클래스의 인스턴스를 생성합니다.
    const neu = new User('Neu', 'Park')
    const neo = new User('Neo', 'Park')
    
    // 생성된 인스턴스를 로그로 출력합니다.
    console.log(neu)
    // User {firstName: 'Neu', lastName: 'Park'}
    console.log(neo)
    // User {firstName: 'Neo', lastName: 'Park'}
    
    // getFullName 메서드를 호출하여 사용자 이름을 로그로 출력합니다.
    console.log(neu.getFullName()) // Neu Park
    console.log(neo.getFullName()) // Neo Park




    02. ES6 Class와 프로토타입 비교

    ES6에서 도입된 클래스와 기존의 프로토타입 기반 상속 방식을 비교해보겠습니다.

    문법적 차이:

    1. 클래스 선언

    // 클래스
     class User {
       constructor(name) {
         this.name = name;
       }
     }
    
     // 프로토타입
     function User(name) {
       this.name = name;
     }

     

    2. 메서드 정의

    // 클래스 
    class User { 
    	sayHello() { 
        	console.log(`안녕하세요, ${this.name}입니다.`); 
        } 
     }
    
    // 프로토타입 
    User.prototype.sayHello = function() {
    	console.log(`안녕하세요, ${this.name}입니다.`); 
    };

     

     

    주요 차이점:

    1. 가독성: 클래스는 더 직관적이고 깔끔한 문법을 제공합니다.
    2. 호이스팅: 클래스는 호이스팅되지 않지만, 함수 선언은 호이스팅됩니다.
    3. 엄격 모드: 클래스 내부 코드는 자동으로 엄격 모드로 실행됩니다.
    4. 생성자: 클래스는 new 키워드 없이 호출할 수 없습니다.


    유사점:

    1. 내부 동작: 클래스도 결국 프로토타입 기반으로 동작합니다.
    2. 인스턴스 생성: 둘 다 new 키워드로 인스턴스를 생성합니다.

    클래스 는 프로토타입 기반 상속의 "문법적 설탕" 입니다. 더 명확하고 사용하기 쉬운 객체 지향 프로그래밍 방식을 제공합니다.



    03. Getter, Setter

    Getter와 Setter는 객체 지향 프로그래밍에서 중요한 개념입니다.

    Getter

    • Getter는 객체의 속성 값을 읽는 메서드입니다.
    • 속성에 접근할 때 자동으로 호출됩니다.
    • get 키워드를 사용하여 정의합니다.


    Setter

    • Setter는 객체의 속성 값을 설정하는 메서드입니다.
    • 속성에 값을 할당할 때 자동으로 호출됩니다.
    • set 키워드를 사용하여 정의합니다.


    장점

    1. 데이터 검증: 값을 설정하기 전에 유효성을 검사할 수 있습니다.
    2. 계산된 속성: 다른 속성을 기반으로 값을 동적으로 계산할 수 있습니다.
    3. 캡슐화: 내부 구현을 숨기고 인터페이스만 노출할 수 있습니다.
    // User 클래스 선언
    class User {
      // 생성자 메서드
      constructor(first, last) {
        this.firstName = first
        this.lastName = last
      }
      // fullName 속성의 Getter 메서드
      get fullName() {
        return `${this.firstName} ${this.lastName}`
      }
      // fullName 속성의 Setter 메서드
      set fullName (value) {
        ;[this.firstName, this.lastName] = value.split(' ')
      }
    }
    
    // User 클래스의 인스턴스 생성
    const neu = new User('Neu', 'Park')
    // fullName 속성의 Getter 메서드 호출
    console.log(neu.fullName)
    
    // fullName 속성의 Setter 메서드 호출
    neu.fullName = 'Neo Anderson'
    // fullName 속성의 Getter 메서드 호출
    console.log(neu.fullName)




    04. 정적 메소드

    프로토타입 메소드와 정적 메소드는 클래스에서 사용되는 두 가지 다른 유형의 메소드입니다.

    프로토타입 메소드

    • 인스턴스에서 직접 호출할 수 있습니다.
    • 객체의 프로토타입에 정의됩니다.
    • 인스턴스 속성에 접근할 수 있습니다.
    • 'this'는 메소드를 호출한 인스턴스를 가리킵니다.


    정적 메소드

    • 클래스 자체에서 호출됩니다.
    • 'static' 키워드를 사용하여 정의합니다.
    • 인스턴스 속성에 직접 접근할 수 없습니다.
    • 'this'는 클래스 자체를 가리킵니다.


    차이점

    1. 호출 방식: 프로토타입 메소드는 인스턴스에서, 정적 메소드는 클래스에서 호출합니다.
    2. 인스턴스 접근: 프로토타입 메소드는 인스턴스 속성에 접근 가능하지만, 정적 메소드는 불가능합니다.
    3. 메모리 사용: 프로토타입 메소드는 모든 인스턴스가 공유하지만, 정적 메소드는 클래스에 하나만 존재합니다.

    각 메소드 유형은 상황에 따라 적절히 선택하여 사용해야 합니다.

    class User {
      constructor(first, last) {
        this.firstName = first
        this.lastName = last
      }
      getFullName() { // prototype 메소드
        return `${this.firstName} ${this.lastName}`
      }
      static isUser(user) { // 정적 메소드
        if (user.firstName && user.lastName) {
          return true
        }
        return false
      }
    }
    
    const neu = new User('Neu', 'Park')
    const neo = new User('Neo', 'An')
    const lewis = {
      name: 'lewis Yang',
      age: 85
    }
    
    console.log(neu)
    console.log(neo)
    console.log(User.isUser(neu)) // true
    console.log(User.isUser(lewis)) // false




    05. 상속과 instanceof

    자바스크립트에서 클래스는 상속을 지원합니다.

     

    상속은 한 클래스가 다른 클래스의 속성과 메서드를 상속받는 것을 의미합니다.

     

    예를 들어, '자전거' 클래스가 '운송수단' 클래스를 상속받으면, '자전거' 클래스는 '운송수단' 클래스의 모든 속성과 메서드를 사용할 수 있습니다.

     

    이를 통해 코드의 재사용성을 높이고, 유지보수를 쉽게 할 수 있습니다.

     

     

     

    instanceof 연산자는 객체가 특정 클래스의 인스턴스인지 확인하는 데 사용됩니다.

     

    예를 들어, '자전거' 클래스의 인스턴스가 '자전거' 클래스의 인스턴스인지 확인하려면, 'instanceof' 연산자를 사용합니다.

     

    이를 통해 객체가 어떤 클래스의 인스턴스인지 확인하고, 그에 따라 적절한 동작을 수행할 수 있습니다.

    // * 운송수단
    class Vehicle {
      constructor(acceleration = 1) {
        this.speed = 0
        this.acceleration = acceleration
      }
      accelerate() {
        this.speed += this.acceleration
      }
      decelerate() {
        if (this.speed <= 0) {
          console.log('정지!')
          return
        }
        this.speed -= this.acceleration
      }
    }
    
    // * 자전거
    class Bicycle extends Vehicle {
      constructor(price = 100, acceleration) {
        super(acceleration)
        this.price = price
        this.wheel = 2
      }
    }
    
    const bicycle = new Bicycle(300)
    bicycle.accelerate()
    bicycle.accelerate()
    console.log(bicycle)
    console.log(bicycle instanceof Bicycle) // true
    console.log(bicycle instanceof Vehicle) // true
    
    
    // * 자동차
    class Car extends Bicycle {
      constructor(license, price, acceleration) {
        super(price, acceleration)
        this.license = license
        this.wheel = 4
      }
      // 오버라이딩
      accelerate() {
        if (!this.license) {
          console.error('무면허!')
          return
        }
        this.speed += this.acceleration
        console.log('가속!', this.speed)
      }
    }
    
    const carA = new Car(true, 7000, 10)
    const carB = new Car(false, 4000, 6)
    carA.accelerate() // 가속! 10
    carA.accelerate() // 가속! 20
    carB.accelerate() // 무면허 !
    console.log(carA)
    console.log(carB)
    console.log(carA instanceof Car) // true
    console.log(carA instanceof Bicycle) // true
    console.log(carA instanceof Vehicle) // true
    
    
    // * 보트
    class Boat extends Vehicle {
      constructor(price, acceleration) {
        super(acceleration)
        this.price = price
        this.motor = 1
      }
    }
    
    const boat = new Boat(10000, 5)
    console.log(boat)
    console.log(boat instanceof Boat) // true
    console.log(boat instanceof Vehicle) // true
    console.log(boat instanceof Bicycle) // false




    06. instanceof 와 constructor

    instanceof 키워드는 클래스의 인스턴스 여부를 확인하는 데 사용됩니다.

     

    이를 통해 특정 클래스의 인스턴스인지, 또는 그 클래스를 상속받은 클래스의 인스턴스인지 확인할 수 있습니다.

     

    예를 들어, class B extends A인 경우, b instanceof Atrue를 반환합니다.

     

    즉, instanceof는 클래스의 상속 계층 구조를 고려하여 비교를 수행합니다.

     

     

    반면, constructor 속성과 일치연산자(===)를 사용하면, 특정 클래스의 인스턴스인지 여부를 더 정확하게 확인할 수 있습니다.

     

    constructor 속성은 객체의 생성자 함수를 반환합니다.

     

    따라서, a.constructor === A와 같이 사용하면, aA 클래스의 직접적인 인스턴스인지 여부를 확인할 수 있습니다.

     

    이 방법은 instanceof와 달리, 클래스의 상속 계층 구조를 고려하지 않습니다.

     

    즉, aA 클래스를 직접 상속받지 않더라도, A 클래스를 상속받은 다른 클래스의 인스턴스라면 false를 반환합니다.

    class A {
      constructor() {}
    }
    
    class B extends A {
      constructor() {
        super()
      }
    }
    
    class C extends B {
      constructor() {
        super()
      }
    }
    
    // a 는 하나의 인스턴스
    const a = new A() // 생성자 함수
    const b = new B()
    const c = new C()
    
    console.log(a instanceof A) // true
    console.log(a instanceof B) // false
    
    console.log(b instanceof A) // true
    console.log(b instanceof B) // true
    console.log(b instanceof C) // false
    
    console.log(c instanceof A) // true
    console.log(c instanceof B) // true
    console.log(c instanceof C) // true
    
    console.log(c.constructor === A) // false
    console.log(c.constructor === B) // false
    console.log(c.constructor === C) // true

    'Language > JavaScript' 카테고리의 다른 글

    [JS] 09. 함수  (1) 2024.10.21
    [JS] 08. 조건문, 반복문  (1) 2024.10.18
    [JS] 07. 구조 분해 할당, 선택적 체이닝  (0) 2024.10.17
    [JS] 06. 연산자  (1) 2024.10.15
    [Js] 05. 데이터 etc  (0) 2024.10.14