객체 지향 프로그래밍

📅 TIL #140




🎯 Achievement Goals

  1. 객체 지향 프로그래밍
  2. 프로토타입 객체
  3. 프로토타입 체이닝
  4. OOP 사용 경험







객체 지향 프로그래밍


자바스크립트는 명령형, 함수형, 프로토타입 기반 객체 지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어이다. 자바스크립트는 원시 타입을 제외하고 모든 것은 객체로 이루어져 있다.


객체 지향 프로그래밍은 프로그램을 명령어 또는 함수의 목록으로 보는 전통적인 명령형 프로그래밍의 절차지향적 관점에서 벗어나 여러 개의 독립적 단위, 즉 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임을 말한다.


예시를 들어보자. 사람마다 다양한 속성을 가지고 있다. 그 속성 중에서도 “이름”과 “주소”라는 속성에만 관심이 있다고 하자. 이처럼 다양한 속성 중에서 프로그램에 필요한 속성만 간추려 내어 표현하는 것을 우리는추상화(abstraction)이라고 한다.


const Me = {
  name: "useong",
  address: "Seoul",
};

console.log(Me) {name: "useong", address: "Seoul"}


이때 개발자는 이름과 주소 속성으로 표현된 객체(object)인 Me를 다른 객체와 구별하여 인식할 수 있다. 이처럼 속성을 통해 여러 개의 값을 하나의 단위로 구성한 복합적인 자료구조를 객체라 하며, 객체 지향 프로그래밍은 독립적인 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임이다.



객체 지향에서 상속이란?


상속은 객체지향 프로그램의 핵심 개념으로 어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용할 수 있는 것을 말한다. 아래의 코드를 통해 상속의 개념을 더 이해하고자 한다.


// 첫번째 코드 (잘못된 예)
function Multiply(w, h) {
  this.width = w;
  this.height = h;

  this.getArea = function () {
    // 넓이를 나타낸다.
    return this.width * this.height;
  };
}

const rectangle1 = new Multiply(2, 3);
const rectangle2 = new Multiply(3, 2);

console.log(rectangle1.getArea === rectangle2.getArea);
// false


기본적으로 Multiply 생성자 함수가 생성하는 모든 객체(인스턴스)는 w, h 프로퍼티와 getArea 메서드를 갖는다. 그런데 동일한 인스턴스에 동일한 메서드를 매번 생성할 필요가 있을까?


현재 w, h의 프로퍼티값은 rectangle1과 rectangle2이 서로 다르다. 동일한 인스턴스에 동일한 메서드가 필요하다면 메서드는 공유를 해서 사용하는 것이 옳다고 볼 수 있다.


Multiply 생성자 함수는 인스턴스를 생성할 때마다 getArea 메서드를 중복 생성하고 모든 인스턴스가 중복 소유한다.




// 두번째 코드 (좋은 예)
function Multiply(w, h) {
  this.width = w;
  this.height = h;

  Multiply.prototype.getArea = function () {
    // 넓이를 나타낸다.
    return this.width * this.height;
  };
}

const rectangle1 = new Multiply(2, 3);
const rectangle2 = new Multiply(3, 2);

console.log(rectangle1.getArea === rectangle2.getArea);
// true


결론부터 말하자면 자바스크립트는 프로토타입 (prototype)을 기반으로 상속을 구현한다.


두개의 예시 코드가 있고 하나는 false, 다른 하나는 true이다. 이 둘의 차이점은 중복으로 메서드를 생성했는가, 아니면 prototype의 프로퍼티와 메서드를 상속받아서 사용했는가에 있다.


프로토타입


getArea 메서드는 단 하나만 생성되어 프로토타입인 Multiply.prototype에 할당되어 있다. 따라서 Multiply 생성자 함수가 생성하는 모든 인스턴스는 getArea 메서드를 상속받아 사용할 수 있다.


이러한 상속 코드는 재사용이란 관점에서 매우 유용하다고 볼 수 있다. 모든 인스턴스가 공통으로 사용할 메서드를 미리 구현만 해놓으면 앞으로 생성되는 인스턴스는 메서드를 가져다 쓰기만 하면 되기 때문이다.






OOP 사용 경험


코드스테이츠에서 실제로 객체 지향 코드를 활용하여 과제를 수행한 경험이 있다. 이해를 돕기 위해 살짝 코드를 변경했다.


// Grub.js
const Grub = function () {
  this.food = "jelly";
};

// prototype에 eat 메서드 생성
Grub.prototype.eat = function () {
  return "Mmmmmmmmm" + this.food;
};

// Bee.js
const Bee = function () {
  // Grub의 this 값과 메서드를 전달받는다.
  Grub.call(this);
};

// 전달받은 Grub 메서드 재사용
Bee.prototype.eat = function () {
  return Grub.prototype.eat();
};

// Bee 프로토타입에 Grub 프로토타입 객체 생성
Bee.prototype = Object.create(Grub.prototype);
Bee.prototype.constructor = Bee;

const bee = new Bee();
bee.eat();

// 'Mmmmmmmmmjelly'


Grub를 call로 this 값을 전달받으면서 메서드도 같이 전달 받는다. 그래서 메서드들의 재사용/공유가 가능하며 중복을 방지할 수 있는 장점을 배운 기억이 있다.


이게 올해 3월 2일에 작성한 코드인데 다시 보니 기분이 정말 새로웠다.. 코드를 보며 객체 지향의 장점을 직접 깨달을 수 있어서 좋았다.



레퍼지토리