4 분 소요

객체 지향 프로그래밍

  • 객체 지향 프로그래밍은 하나의 모델이 되는 청사진을 만들고, 그 청사진을 바탕으로 한 객체를 만드는 프로그래밍 패턴이다.
  • 이 청사진을 바탕으로 한 객체는 인스턴스 객체, 줄여서 인스턴스라고 부른다. 그리고 청사진은 클래스라 부른다.
  • 새로운 인스턴스를 만들 때, 일반적인 함수를 정의하듯 만들지만, new 키워드를 써서 만든다.
  • ES6에서는 class라는 키워드가 도입이 되어 이 키워드를 주로 사용한다.
  • 클래스 안에 있는 함수는 생성자 함수로 인스턴스가 만들어질 때 실행되는 코드이고, return 값을 만들지 않는다.
  • class에서는 인스턴스 객체를 this로 많이 사용한다.
class Car {
  // 클래스 만들기
  constructor(brand, name, color) {
    // 인스턴스 만들기 함수
    this.brand = brand;
    this.name = name;
    this.color = color;
  }

  drive() {
    // 메소드 만들기
  }

  refuel() {
    // 메소드 만들기
  }
}

let avante = new Car("hyundai", "avante", "black");
let mini = new Car("bmw", "mini", "white");

constructor

  • constructor 메서드는 클래스의 인스턴스 객체를 생성하고 초기화하는 메서드이다.

OOP Basic Concepts

1. 캡슐화

  • 데이터와 기능을 하나의 단위로 묶는 것이다. (인스턴스 + 메소드)
  • 은닉화 : 내부 데이터나 내부 구현이 외부로 노출되지 않도록 만드는 것이다.
  • 느슨한 결합에 유리 : 언제든 구현을 수정할 수 있음
  • 느슨한 결합 : 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합하는 것을 의미한다.
  • 코드나 데이터의 은닉에 포커스
class Car {
  constructor(name, brand, color) {
    this.name = name;
    this.brand = brand;
    this.color = color;
    this.distanse = 0;
  }

  drive(distanse) {
    this.distanse += distanse;
    console.log(`${this.name}${this.distanse}km 움직였습니다.`);
  }
}

const mini = new Car("mini", "bmw", "red");
console.log(mini.name); // mini
mini.drive(5); // mini가 5km 움직였습니다.
console.log(mini.distanse); // 5
  • Car라는 클래스를 만들어 인스턴스와 메소드를 한 단위로 묶었다.
  • 인스턴스와 메소드들을 언제든지 수정할 수 있고, Car가 움직이고, brand, color등 Car에 의미하는 것들을 모아 결합한 것을 보아 느슨한 결합을 한 것을 볼 수 있다.

은닉화

  1. ‘_’ 사용
class SomeConstructor() {
  this._privateProp = 'dont touch this';
  this.publicProp = 'you can touch this';
}
  • 일반적으로 js는 객체의 private 한 속성을 만들 수 없었다. 그래서 인스턴스에 ‘_‘를 붙이면 외부에서 사용하면 안되는 약속을 가지고 private하게 만들었다.
  1. ’#’ 사용

자바스크립트에서도 언어가 제공하는 클래스에 private 속성을 만들 수 있게 되었다. TC39의 스펙문서를 토대로 간단하게 특징을 요약하자면 아래와 같다.

  • Stage-3 단계에 있는 스펙으로 특별한 결격 사유가 없는 한 표준 스펙이 될 것이다. 물론 변경되거나 개선될 여지는 있다.
  • private과 같은 키워드를 사용하지 않는다. 대신 # 즉 샵 프리픽스를 사용한다. 키워드가 아니라 프리픽스다. 속성 명 앞에 #이 붙으면 Private 필드로 동작한다.
  • Class Field Decalarations 스펙의 일부다. public과 다른 점은 클래스의 필드 선언을 통해서만 만들 수 있다. 즉 동적으로 객체에 private 필드를 추가할 수 없다.
  • 메서드에는 제한적이다. 메서드 선언으로 사용할 수 없다. private 메서드를 만들려면 함수 표현식으로 정의해야 한다.

    • 어디까지나 현재로서는 그렇다는 말이다. 스펙이 업데이트될 수도 있다. (Class fields and private methods: Stage 3 update)
  • Computed Property Name을 사용할 수 없다. #foo 자체만 식별자로 허용되고 ‘#[fooName]’ 이건 문법 오류다.
  • 모든 Private 필드는 소속된 클래스에 고유한 스코프를 갖는다. 그렇기 때문에 독특한 특징이 있다.(그 특징은 뒷부분에서 다룬다)
class Human {
  #age = 10;
}

const person = new Human();
console.log(person.#age); // // Error TS18013: Property '#age' is not accessible outside class 'Human' because it has a private identifier.
  • Human 클래스에 #age라는 인스턴스를 만들어서 console.log를 하였더니 클래스 외부에서 접근할 수 없다고 에러 메세지가 출력된다.
class Human {
  #age = 10;

  getAge() {
    return this.#age;
  }

  printAge() {
    return this.age;
  }
}

const person = new Human();
console.log(person.printAge()); // Error TS2551: Property 'age' does not exist on type 'Human'. Did you mean '#age'?
console.log(person.getAge()); // 10
  • printAge에 #을 안붙히고 printAge 메소드를 실행 시켰더니 접근할 수 없다고 에러 메세지가 출력된다.
  • getAge에는 #을 붙히고 getAge 메소드를 실행 시켰다. 이번엔 정상적으로 출력이 됐다.
class Human {
  #age = 10;

  getAge() {
    return this.#age;
  }
}

class Person extends Human {
  getFakeAge() {
    return this.#age - 3; // Property '#age' is not accessible outside class 'Human' because it has a private identifier.
  }
}
  • 상속 받은 클래스는 어떨까? 물론 에러 메세지가 뜬다. 이유는 해당 private 속성이 정의된 클래스를 제외하고는 어디에서도 접근이 불가능 하기 때문이다.

2. 상속

  • 부모 클래스의 특징을 자식 클래스가 물려받는 것이다.
  • extends와 super을 사용하여 상속한다.
class Car {
  constructor() {
    this.name = "avante";
    this.brand = "hyandai";
    this.color = "white";
  }
}

class Model extends Car {
  constructor(model) {
    super();
    this.model = model;
  }
}

const avante = new Model(2020);
console.log(avante); // Model {name: 'avante', brand: 'hyandai', color: 'white', model: 2020}
console.log(avante.name); // avante
console.log(avante.model); // 2020
  • Car 클래스에서 인스턴스를 미리 값을 지정해 주었다.
  • avante에 Model 인스턴스를 만들면, Car에서 지정해 주었던 인스턴스의 값을 받을 수 있다.

3. 추상화

  • 내부 구현은 복잡 하지만, 실제로 노출되는 부분은 단순하게 만든다는 개념이다.
  • 필요하지 않은 메소드 등을 노출시키지 않고, 단순한 이름으로 정의하는 것에 포커스
  • 클래스 정의 시, 메소드와 속정만 정의한 것을 인터페이스라 부른다.

4. 다형성

  • 다양한 형태를 가질 수 있다는 의미이다.
class Car {
  constructor(name, brand, color) {
    this.name = name;
    this.brand = brand;
    this.color = color;
    this.distanse = 0;
  }
}

const mini = new Car("mini", "bmw", "black");
console.log(mini.name); // mini
const avante = new Car("avante", "hyandai", "white");
console.log(avante.brand); // hyandai
console.log(mini.brand); // bmw
  • 클래스를 사용하여 mini의 인스턴스와 avante의 인스턴스를 만들었다.
  • 하나의 클래스를 이용하여, 전달인자를 다르게 하여 다양한 형태의 클래스 인스턴스를 만들 수 있다.

댓글남기기