(SEB_FE) Section2 Unit2 객체 지향 프로그래밍(OOP, Object-oriented programming)

PYM·2023년 3월 15일
0

(SEB_FE) SECTION2

목록 보기
2/19
post-thumbnail
  • 클로저 모듈 패턴에 대해 설명할 수 있다.
  • 클래스와 인스턴스에 대해 설명할 수 있다.
  • 클래스 문법을 이용할 수 있다.

🏀객체 지향 프로그래밍(OOP, Object-oriented programming)

  • 하나의 모델이 되는 청사진(blueprint)을 만들고, 그 청사진을 바탕으로 한 객체를 만드는 프로그래밍 패턴

  • 객체 지향 프로그래밍은, 절차 지향 프로그래밍(Procedural Programming)과는 다르게 데이터와 기능을 한곳에 묶어서 처리한다

    • 여기서 잠깐! 절차 지향 프로그래밍이란?
      물이 위에서 아래로 흐르는 것처럼 순차적 처리가 중요시 되어 프로그램 전체가 유기적으로 연결되도록 만드는 프로그래밍 기법
  • "객체" 안에 속성과 메서드가 들어있는데 이때 이 객체는 Javascript의 내장 type인 object가 아니라 class 라고 부른다.


🏀클로저 모듈 패턴

/*counter1 객체 안에 increase, decrease, getValue라는 메서드가 적혀있다!
[counter1.메서드명()]과같이 호출*/

let counter1 = {
  value: 0,
  increase: function() {
    this.value++ // 메서드 호출을 할 경우, this는 counter1을 가리킴
  },
  decrease: function() {
    this.value--
  },
  getValue: function() {
    return this.value
  }
}

counter1.increase()
counter1.increase()
counter1.increase()
counter1.decrease()
counter1.getValue() // 2
  • 이처럼 단순 객체를 사용한 경우, counter1은 단 하나의 객체만을 만들 수 있다.
  • 만약 똑같은 기능을 하는 카운터가 여러 개가 필요할 경우엔 계속 같은 코드를 복사 붙여넣기 해야하기 때문에 "재사용성"이 저하된다.

그럼 어떻게 해야 똑같은 기능을 하는 객체를 여러개 만들 수 있을까?
➡️ 클로저를 사용하자!

function makeCounter() {
  let value = 0;
  return {
    increase: function() {
      value++;
    },
    decrease: function() {
      value--;
    },
    getValue: function() {
      return value;
    }
  }
}

let counter1 = makeCounter()
counter1.increase()
counter1.getValue() // 1

let counter2 = makeCounter()
counter2.decrease()
counter2.getValue() // -1
  • 이렇게 클로저 모듈 패턴을 사용하면 코드의 재사용성이 증대된다!

🏀클래스와 인스턴스

  • 이 글의 시작에서 객체 지향 프로그래밍하나의 모델이 되는 청사진(blueprint)을 만들고, 그 청사진을 바탕으로 한 객체를 만드는 프로그래밍 패턴 라고 했었다.

  • 만약 자동차를 만든다고 하자. "바퀴 네개와 핸들, 그리고 엔진이 필요하다" 라는 거의 모든 자동차들에게 동일하게 적용되는 청사진은 class에 해당하고,
    그 청사진을 바탕으로 만들어 낸 자동차들은 인스턴스 객체(instance object)이다.

🏅클래스와 인스턴스 생성 방법

  • 이 객체(not object literal)는 일반적인 함수를 정의하듯이 만들 수 있는데, 한가지 다른 점이 있다. 바로 new 키워드를 사용해서 생성한다는 점!
    ➡️ 이게 바로 새로운 인스턴스를 만드는 방법이다.

  • 클래스는 일반적인 다른 함수와 구분하기 위해 보통 대문자로 시작하며 일반명사로 만드는 규칙이 있다.
    (일반적인 함수는 적절한 동사를 포함하고 소문자로 시작)

  • ES6 문법에 클래스를 만드는 새로운 문법이 도입되었다! 최근에는 이 방법을 주로 사용한다. 아래는 각 방법을 통한 클래스의 정의.

    • function 정의 ➡️ function Car (color) { code }
    • class키워드 정의 ➡️ class Car { constructor(color) { code } }

    이러한 함수들을 생성자(constructor) 함수라고 부른다.

  • 인스턴스를 만들 때에는 new 키워드를 사용. 즉시 생성자 함수가 실행되며, 변수에 클래스의 설계를 가진 새로운 객체, 즉 인스턴스가 할당된다.

    • 인스턴스 ➡️ let sonata = new Car('silver');

    각각의 인스턴스는 클래스의 고유한 속성과 메서드를 가지게 된다.

🏅속성과 메서드란❓

자동차의 속성 ➡️ 브랜드, 차 이름, 색상, 현재 연료 상태, 최고 속력 등등...
자동차의 메서드 ➡️ 연료 주입, 속력 설정, 운전 등등... (객체에 딸린 함수)

this Keyword

  • this는 인스턴스 객체를 의미. 그 인스턴스 내부에서 그 인스턴스의 매서드에 접근할 때 사용할 수 있다. this.메소드명 = value; 처럼!

🏅ES5 클래스 작성 문법

function으로 정의된 클래스에 메서드를 추가하기 위해서는 prototype을 이용

function Car (brand, name, color) { /*인스턴스가 만들어질때 실행될 코드*/ }

Car.prototype.refuel = function() {
	// 연료 공급을 구현하는 코드 
}

🏅ES6 클래스 작성 문법

prototype 사용하지 않고 생성자 함수와 함께 class 키워드 안쪽에 묶어서 정의

class Car {
  constructor(brand, name, color) { /*인스턴스가 만들어질때 실행될 코드*/ }
  refuel() {
    // 연료 공급을 구현하는 코드 
  }, 
  drive() {
    // 운전을 구현하는 코드 
  } 
}

🏅클래스에서 생성한 메서드를 인스턴스에서 사용하는 방법

let sonata = new Car('hyundai', 'sonata', 'silver');
sonata.color; // "silver"
sonata.drive(); // sonata가 운전을 시작한다 

근데 이 사용법... 어디선가 본 듯 하다!!
⬇️⬇️ 바로 이전까지 학습했던 배열에서 이와 동일한 사용법을 쓴 적이 있다 ⬇️⬇️

// 아래 줄은 let arr = new Array (1, 2, 3, 4, 5); 와 같다
// 즉 배열을 정의한 것은 Array 클래스의 인스턴스를 만든 것! 
let arr = [1, 2, 3, 4, 5];

// 즉 아래 줄들은 Array.prototype.length() 와 Array.prototype.push로 
// Array 클래스의 메서드들인 것. 
arr.length; // 5 
arr.push(6);

+plus

JavaScript에서만 유효한 용어들의미
Prototype모델의 청사진을 만들 때 쓰는 원형 객체(Original form)
constructor인스턴스가 초기화될 때 실행하는 생성자 함수
this함수가 실행될 때, 해당 scope마다 생성되는 고유한 실행 context(execution context)로 new 키워드로 인스턴스 생성 시 해당 인스턴스가 바로 this의 값이 된다.

🏀객체 지향 프로그래밍 기본 개념 (4가지)

🏅 1. 캡슐화(Encapsulation)

  • 외부에서 앞서 말했던 데이터(속성)와 기능(메서드)을 따로 정의하는 것이 아닌, 하나의 객체 안에 넣어서 묶는 것
    ➡ 데이터(속성)와 기능(메서드)들이 느슨하게 결합

  • 느슨한 결합 ➡ 코드 실행 순서에 따라 절차적으로 코드를 작성하는 것이 아니라, 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합하는 것

캡슐화는 은닉화의 특징도 포함한다.

  • 은닉화 ➡ 내부 데이터나 내부 구현이 외부로 노출되지 않도록 만드는 것
    • 디테일한 구현, 데이터는 숨기고, 객체 외부에서 필요한 동작(메서드)만 노출

캡슐화는 코드의 복잡성을 낮추고 재사용성을 높여준다.

🏅 2. 추상화(Abstraction)

  • 내부 구현은 아주 복잡한데, 실제로 노출되는 부분은 단순하게 만드는 것

  • 인터페이스를 단순화 할 수 있다.

    • 인터페이스: 클래스 정의 시, 메서드와 속성만 정의한 것
  • 캡슐화가 코드나 데이터의 은닉에 포커스가 맞춰져있다면, 추상화는 클래스를 사용하는 사람이 필요하지 않은 메서드 등을 노출시키지 않고, 단순한 이름으로 정의하는 것에 포커스

추상화는 코드의 복잡성을 낮추고, 사용을 단순화 해, 변화에 대한 영향을 최소화한다.

🏅 3. 상속(Inheritance)

  • 부모 클래스의 특징을 자식 클래스가 물려받는 것. 정확하게는,
    "기본 클래스(base class)의 특징을 파생 클래스(derived class)가 상속받는 것"

  • 사람 클래스가 있고 학생 클래스가 있을 때, 학생 역시 사람이기 때문에 상속을 이용하여 학생 클래스는 사람 클래스를 상속받을 수 있다.
    학생 클래스에는 학습 내용, 공부하다 와 같은 속성/메서드를 추가할 수 있다.

상속을 통해 불필요한 코드를 줄여 재사용성을 높인다.

🏅 4. 다형성(Polymorphism)

  • "말하다"라는 동작의 본질은 다 똑같이 입으로 소리를 내는 것이지만, 각기 다른 동물들이 "말할 때" 제각각의 소리를 내는 것처럼,
    객체 역시 똑같은 메서드라 하더라도, 다른 방식으로 구현될 수 있다.
// 만약 다형성이 없다면...
if (type === 'select') {
  renderSelect()
}
else if (type === 'text') {
  renderTextBox()
}
else if (type === 'checkbox') {
  renderCheckBox()
}
//...
  • 다형성이 없다면 이와 같이 부모 클래스에 종류별로 분기를 시켜야 함
  • 다형성이 있으면 이렇게 하지 않고 부모 클래스에 render() 메서드 있게 해서 자식의 종류에 따라 다르게 rendering이 가능.
    (TextBox는 가로로 긴 네모 상자와 커서가 있는 형태, Select 박스는 눌렀을 때 선택지 등)

다형성으로 인해
동일 메서드에 대해 조건문 대신 객체의 특성에 맞게 달리 작성하는 것이 가능하다.

profile
목표는 "함께 일하고 싶은, 함께 일해서 좋은" Front-end 개발자

0개의 댓글