OOP개념과 Prototype

📅 TIL #35



🎯 Achievement Goals


  • OOP(Object Oriented Programming)가 무엇인지 이해할 수 있다.


  • JavaScript에서 Prototype은 무엇이고 왜 사용해야 이해할 수 있다.
    • Prototype Chain




👉 OOP (Object Oriented Programming)


OOP란 ?


204E831F4CA35FC85D

OOP란 한국말로 직역하면 객체 지향 프로그래밍이라는 뜻이다.

객체지향 프로그래밍 이란 캡슐화, 다형성, 상속 을 이용하여 코드 재사용을 증가시키고, 유지보수를 감소시키는 장점을 얻기 위해서 객체들을 연결 시켜 프로그래밍 하는 것 이다.


즉, OOP는 결국 프로그램을 어떻게 설계할 것인가?에 대한 방법이다. 설계 패턴이기 때문에 장단점이 존재하고 가장 좋은 설계방법이라고 말할 수도 없고, 함수형 프로그래밍이니 OOP니 하는 것 보다는 모두 다 알고 있는 것이 가장 좋은 것 같다.


오늘은 객체 지향프로그램에서도 주요 컨셉인 캡슐화, 상속, 추상화, 다형성에 대해서 블로깅을 할 예정이다!



캡슐화 (Encapsulation) 의 특징

캡슐화


캡슐화란? 데이터와 함수들을 하나로 묶어 객체 단위로 프로그램을 짜는 방식이다. 즉 연관된 데이터와 함수들을 캡슐처럼 하나의 테두리로 묶는 것이다.

어떠한 클래스를 사용할 때 내부 동작이 어떻게 돌아가는지 모르더라도 사용법만 알면 쓸 수 있도록 클래스 내부를 감추는 기법이다.

클래스 내부의 데이터를 감추는 것을 정보 은닉(Information Hiding)이라고 한다.

클래스에서 만들어진 객체가 특정한 목적을 잘 수행할 수 있도록 사용해야 할 변수와 메소드들을 잘 구성해야 한다.

참고로 캡슐화와 정보은닉은 동일한 개념은 아니다. 캡슐화를 하면 불필요한 정보를 감출 수 있기 때문에, 정보은닉을 할 수 있다는 특징이 있다는 것이다.

예를 들어, 전자 제품을 이용하는데 전자 제품 내부 회로(private으로 정의된 속성)를 알 필요가 있다는 뜻이다. 사용자의 입장에서는 전자 제품의 조작기능, 즉 public으로 정의된 속성만 알면 된다.



상속(inheritance) 의 특징

상속


한 클래스가 다른 클래스의 데이터와 메소드를 그대로 물려받아서 쓰는 것이다.

위 사진을 보더라도 고양이와 사자는 다른 클래스이지만, 상위 클래스를 상속하는 방식은 정의된 데이터와 메소드 코드를 그대로 물려받아 재사용하여 중복 작성을 줄였다. 그리고 기능을 추가하였다.

즉, 상속이 필요한 이유는 같은 기능을 중복 작성하는 작업을 줄이고, 거기서 새 기능을 추가하거나 상속받은 기능을 변형하기 위함이다.



다형성 (Polymorphism) 의 특징


poly(많은) 와 morth(형태) 즉 다양한 형태을 가질 수 있다는 뜻이다.

다른 클래스로부터 상속받은 기능을 자신에게 맞는 형태로 변형하여 재정의(오버라이딩) 하는 과정과 클래스 내에서도 하나의 기능에 조금씩 변형을 하여 중복 작성(오버로딩)하는 과정이 있다.

재정의(오버라이딩)은 하나의 기능이 사용하는 주체가 어떤 클래스의 객체인지에 따라 다른 형태로 표현된다.

중복 작성(오버로딩)은 하나의 기능이 사용하는 방법에 따라 다른 형태로 표현된다.

다형성은 해당 클래스에 맞춰 기능을 정의하여 객체를 사용해야 할 필요성을 줄이는 것이다. 객체의 특성에 맞게 달리 작성하는 것이 가능하게 한다.

다형성1


또 중요한 한가지는 객체의 기능이 다양하게 작동할 수 있는 성질이다. 기능의 의미는 크게 변하지 않고 오로지 형태만 변형된다는 점이다.


다형성2


이렇듯 상속은 다형성을 최대한 효과적으로 구현하기 위해 가능한 계층적인 구조를 위주로 설계된다.



추상화 (Abstraction) 의 특징


추상화는 객체들이 가진 공통의 특성들을 파악하고 불필요한 특성들을 제거하는 과정을 말한다.

객체들이 가진 동작들을 기준으로 이용자들이 동작만 쉽게 구동할 수 있도록 한다.

즉 추상화는 내부 구현은 아주 복잡한데, 노출되는 부분은 단순하게 만든다는 개념이다.




Prototpye


자바스크립트는 프로토타입 기반의 언어이다. 사실 자바스크립트 자체는 OOP를 생각하고 만든 언어는 아니다. Java, Python, Ruby 등 클래스라는 개념이 있는데 최근에 ECMA6 자바스크립트에도 class 문법이 추가가 되었다. 단순히 문법만 추가된 것이지, 클래스 기반으로 바뀐 것은 아니다.

자바스크립트의 모든 객체들은 자신의 부모 역할을 담당하는 객체와 연결되어 있다. 이것은 마치 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있게 한다. 이러한 부모 객체를프로토타입 객체(prototype object)또는 프로토타입(prototype) 이라고 한다.

프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수 있고 그 상위 프로토타입 객체도 마찬가지이다. 이런식으로 계속 상속받는 관계를 이어나가는 것을 프로토타입 체인(prototype chain) 이라고 부르며, 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 것이다.



프로토타입 어떻게 쓰는건가?


function Person() {
  this.hans = 2;
  this.nose = 1;
}
  let lee = new Person()
  let kim = new Person()

  console.log(lee.hans) // 2
  console.log(lee.nose) // 1

  console.log(kim.hans) // 2
  console.log(kim.nose) // 1


prototype 객체는 사전 그대로 원형을 뜻한다. 즉, 원래의 모습을 나타낸다. 현재 this에 넣은 것은 객체 하나를 만들 때마다 메소드도 하나씩 만들어지기 때문에 불필요한 메모리 낭비가 발생한다.

그래서 메모리에는 hans 와 nose가 각각 2개씩해서 총 4개가 할당된다. 이러한 문제를 프로토타입으로 해결할 수 있다.


function Person() {}

  Person.prototype.hans = 2;
  Person.prototype.nose = 1;

  let lee = new Person()
  let kim = new Person()

  console.log(lee.hans) // 2
  console.log(lee.nose) // 1

  console.log(kim.hans) // 2
  console.log(kim.nose) // 1


Person.prototype이라는 빈 Object가 어딘가에 존재하고, Person 함수로부터 생성된 객체 (lee, kim)들은 어딘가에 존재하는 Object에 들어있는 값을 모두 가져다가 쓸 수 있다.

즉, hans와 nose를 어딘가에 빈 공간에 넣어놓고 lee와 kim이 공유해서 사용하는 것이다.


함수를 정의하면 함수만 생성되는 것이 아니라 Prototype Object도 같이 생겨난다.

프로토타입

그리고 생성된 함수는 prototype이라는 속성을 통해 Prototype Object에 접근할 수 있다. 이것은 일반적인 객체와 같으며 기본적인 속성으로 constructorproto를 가지고 있다.




constructor


class는 생성자를 필요로하는데, 이 생성자가 constructor이다. 즉, 생성자 함수 그 자체를 가리킨다.

// 클래스 생성
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}


constructor는 외부에서 접근하여 값을 변경할 수 있다.


class Person {
  constructor (name, age) {
    this.name = name; // publicField
    this.age = age;
  }
}

const person = new Person("useong", 28)

console.log(person.name) // "useong"
console.log(person.age)  // 28

person.age = 25

console.log(person.age) // 25



프로토타입 객체의 확장


프로토타입 객체도 객체이므로 일반 객체와 같이 프로퍼티를 추가/삭제할 수 있다. 그리고 이렇게 추가/삭제된 프로퍼티는 즉시 프로토타입 체인에 반영된다.


function Person(name) {
  this.name = name;
}

let person = new Person("useong")

Person.prototype.niceToMeetYou = function () {
  console.log("Hi! my name is " + this.name);
}

person.niceToMeetYou()  // Hi! my name is useong

이런식으로 메소드를 추가할 수 도 있다.



원시 타입(Primitive type)의 확장

원시 타입은 객체가 아니므로 프로퍼티나 메소드를 직접 추가할 수 없다.

let str = "test";

str.testMethod = function () {
  console.log ("str.testMethod");
}

str.testMethod(); // Uncaught TypeError: str.myMethod is not a function



하지만 String 객체의 프로토타입 객체 String.prototype에 메소드를 추가하면 원시 타입, 객체 모두 사용할 수 있다.


let str = "test";

String.prototype.testMethod = function () {
  return "test Complete";
}

console.log(str.testMethod());      // "test Complete"
console.log('string'.testMethod()); // "test Complete"




이머시브 1주차가 끝이 났다. 오늘 OOP 와 ES6 클래스 키워드들을 배우고나서야 이머시브에 온 걸 직감하는 것 같다. 이번주 주말은 스프린트 복습이 정말로 절실하다. 앞으로도 이머시브에서 뒤쳐지지 않게 효율적으로 공부하고 열심히 복습하자!!




👊 내일의 TIW(today I Will)

ES6 class 키워드 및 super 키워드