프로그래밍 공부/Javascript

객체 지향 프로그래밍: 클래스와 프로토타입 / TIL 21일차

Kevinkb 2021. 10. 5. 18:40

객체 지향 프로그래밍(Object Oriented Programming)

객체 지향 프로그래밍은 프로그램(OOP) 설계 철학 중 하나로 사람이 세계를 보고 이해하는 방법을 흉내낸 방법론이다. 단순히 별개의 변수와 함수로 순차적으로 작동하는 것을 넘어, 데이터의 접근과, 데이터의 처리 과정에 대한 모형을 만들어 내는 방식이다. 즉, 데이터와 기능이 별개로 취급되지 않고, 한번에 처리할 수 있는 방식이다. OOP의 모든 것은 객체로 그룹화되며 아래의 4가지 주요 개념을 통해 재사용성을 얻을 수 있다.

1. 캡슐화 Encapsulation

데이터와 기능을 하나의 단위로 묶는 것

캡슐화는 데이터(속성)와 기능(메소드)을 따로 정의하는 것이 아닌, 하나의 객체 안에 넣어서 묶는 것이다. 데이터(속성)과 기능(메소드)들이 느슨하게 결합되어 있다. 느슨한 결합은 코드 실행 순서에 따라 절차적으로 코드를 작성하는 것이 아니라, 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합하는 것을 의미한다.

은닉화: 구현은 숨기고, 동작은 노출

캡슐화라는 개념에는 "은닉화"의 특징도 포함된다. 은닉화는 내부 데이터나 내부 구현이 외부로 노출되지 않도록 만드는 것이다. 따라서, 은닉화의 특징을 살려서 코드를 작성하면 객체 내 메소드의 구현만 수정하고, 노출된 메소드를 사용하는 코드 흐름은 바뀌지 않도록 만들 수 있다. 반면, 절차적 코드의 경우 데이터의 형태가 바뀔 때에 코드의 흐름에 큰 영향을 미치게 되어 유지보수가 어렵다.

2. 추상화 Abstraction

추상화는 내부 구현은 복잡한데, 실제로 노출되는 부분은 단순하게 만든다는 개념이다.
캡슐화는 코드나 데이터의 은닉을 의미하고 추상화는 단순한 이름으로 정의하는 것을 의미한다.

※인터페이스(Interface)
클래스 정의 시, 메소드와 속성만 정의한 것이 인터페이스이다. 이것이 추상화의 본질이다.

3. 상속 Inheritance

부모 클래스의 특징을 자식 클래스가 물려받는 것이다. 보다 자세한 표현은 '기본 클래스(base class)의 특징을 파생 클래스(derive class)가 상속받는다'가 적합하다. 부모 클래스의 속성과 메소드를 재구현하지 않고 자식 클래스에 상속할 수 있다.

4. 다형성 Polymorphism

"다양한 형태"를 가질 수 있다

같은 이름을 가진 속성 또는 메소드라도 인스턴스의 인자가 달라질 수 있고 그에따라 조금씩 다르게 작동하는 것이 다형성을 의미한다.

주요 개념의 장점

  • 캡슐화는 코드가 복잡하지 않게 만들고, 재사용성을 높임
  • 추상화는 마찬가지로 코드가 복잡하지 않게 만들고, 단순화된 사용으로 인해 변화에 대한 영향을 최소화
  • 상속 역시 불필요한 코드를 줄여 재사용성을 높임
  • 다형성으로 인해 동일한 메소드에 대해 if/else if와 같은 조건문 대신 객체의 특성에 맞게 달리 작성이 가능

Prototype

자바스크립트의 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object) [[Prototype]]를 가진다. 프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지다. 이를 프로토타입 체인(prototype chain)이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간이다. 정확히 말하면 상속되는 속성과 메소드는 각 객체가 아닌 객체의 생성자의 prototype이라는 속성에 정의되어 있다. 즉, prototype는 상속 받아왔고 상속할 속성과 메소드들이 참조된 곳이다. 자바스크립트는 이 프로토타입을 기반으로 상속을 구현하며 불필요한 중복은 제거한다.

// 클래스 선언
class Human {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sleep() {
    console.log(`${this.name}은 잠에 들었습니다`);
  }
}

// 인스턴스 생성
const steve = new Human('steve', 30);

console.log(steve);   //  Human {name: 'steve', age: 30}
console.log(Human.prototype);   // {constructor: class Human, sleep: ƒ sleep()}
console.log(Human.prototype.constructor === Human);      // true
console.log(Human.prototype === kimcoding.__proto__);    // true
console.log(Human.prototype.sleep === kimcoding.sleep);  // true

Prototype chain