JavaScript OOP Class & Instance

근간에 생일인지도 모르고있다가 챙김받은덕에 술독에 저번주 금요일부터 일요일저녁까지 푹 담궈졌더니 정신을 못차렸다. 하지만 이번을 기회로 생일을 챙겨주는 고마운 분들도 좋지만, 우선순위를 정해서 할거부터 해놓고 놀아라는 으른들의 말씀이 떠올랐다. 태윤아 이제 곧 지천명(불혹이란다 누가 나한테 지천명이라고한거야 똥멍청이가)인데 정신좀차리자. 돈많은 백수해야지 이순때부터 놀고먹어야될거아냐.. 그래서 우리는알아야한다. 무엇을? 기계어를. 인간세상의 모습으로 바꿔주는 객체 지향 프로그래밍을 :D


1. OOP

자바때 귀가 아프게 들었던 붕어빵이야기, 객체 지향 프로그래밍은 OOP라고 하면 개발에 관심있는 분들이라면 누구나 한번쯤은 봤을 것이다. Object-oriented programming은 우리네 세상을 보듯이 0과 1인 신호를 원시언어로 원시언어에서 더 보기 좋은 고급언어로, 거기서 더 보기좋게 추상화하여 직관적으로 볼 수 있게 한다.

객체지향적 언어: Java, C#… -> JS는 함수형 프로그래밍입니다.

2. 객체 지향

절차 지향 프로그래밍과 다르게 데이터와 기능을 한곳에 묶어 처리한다. property와 method가 포함된다. Object객체와는 다르고, Class라 칭한다.

3. 클로저 모듈 패턴

3.1. usage

anyClass.anyFunction();

메서드 호출방식을 정의할때는 화살표함수를 쓰지말라고 명시되어 있다. Maxxxxx선생님은 this의 문제를 화살표함수가 해결해주었다고 했다.

function FishBread(){
  this.count = 0; //이 this는 FishBread의 instance

  makeBread(function work(){
      this.count++;   //생성자의 this가 아니라 work의 this임
  });
//이 this와 저this는 다른데 뭐가 누구의 this인지 this지옥이 펼쳐짐


//ECMAScript 3/5 비전역 변수에 할당하여 해결(우회했단 말같아)
function Hunt(){
  var that = this;
  that.count = 0;

  getNumber(function attachSuccess(){
      that.count++;
  });
}

function Marry(){
  this.wife = 0;

  welcomeToHell(() => {
      this.wife = 1;  //Person객체 참조
  });
}
//this가 lexical(정적)임을 감안, this에관한 엄격모드규칙은 무시됨.
var f = () => {'use strict'; return this;}
f() ===  window;  //or 전역 객체
//엄격모드의 나머지 규칙은 그대로 적용

4. 클래스와 인스턴스

자바에서 말하는 객체하면 심심하면 나오는 지겨운 붕어빵을 또 예로들어보자(제일 맛잇게 이해하니까 많이 하겠지?)

  • 하나의 붕어빵 틀(bluePrint 청사진 모델)을 만들고(class)
  • 붕어빵 틀붕어빵(Object 객체)를 만드는(instance)
  • 이것이바로 객체 지향 프로그래밍 패턴
//붕어빵틀(class를 만들고)
function PanOfFishBread(flavor){
    this.flavor = flavor;
    this.price = 0;//초기값
    ...//↑↑↑↑↑↑↑인스턴스 생성될때실행↑↑↑↑↑↑↑

    PanOfFishBread.prototype.make(){
        //붕어빵 굽는 구현 코드
        return 맛잇는붕어빵;
    }
}

//붕어빵을 찍는다.(new ClassName -> Instance 생성됨)
let pizza2_000 = new PanOfFishBread('cheese');
let redBean1_500 = new PanOfFishBread('redBean');
let cream1_800 = new PanOfFishBread('cream');
//맛,5개가격 많이 사주세요 :D
//↑↑↑↑↑↑↑상기코드는 ES5문법↑↑↑↑↑↑↑
//============================================
//↓↓↓↓↓↓↓↓↓ES6문법은 class로 정의(2022기준 많이쓴대요)↓↓↓↓↓↓↓↓↓
class Hunter(){
    constructor(age, name){
        //인스턴스 생성될때 실행
        //##return 없다. 주의
        this.age = age;
        this.name = name;
        this.gender = 'male';
        ...
    }

    ready(){
        //헌팅을하기위해 꽃단장을 구현하는 코드
    }
}
//this는 instance 객체이다.

Java와 상당히 비슷하다. 의도한건지는 모르겠으나 Java와 다르게 동작하고 모양만 비슷하다. prototype같은건 자바에는 존재하지 않는다.

5. 객체 지향 프로그래밍

상기에서 말한 절차적 언어(순차적인 명령의 조합)는 함수는 이동만가능한 설계였단다. 로우레벨의 언어들은 그랬지만 현대적인 고레벨의언어들은 대부분(다그런건 아님) 객체지향의 특징을 가진다. Java, C++, C# 등과 같이 JavaScript도 객체 지향으로 작성이 가능(함수형 프로그래밍이에요)하다.

5.1. OOP

Object oriented programming은 프로그램의 설계 철학이다.

  1. 모든걸 객체로 그룹화 할 수 있다.
  2. 객체는 한번 생성하고 나면 메모리상에서 반환되기전까지 객체내에 모든것이 남아있다.(메모리에 유지된다.)
  3. 객체내에 데이터와 기능이 함께있다. -> method, property있다.
  4. new 객체를 만들때 고유 property를 설정할 수 있다.

JavaScript 내 용어와는 별개로 class를 통해 만들어진 객체를 특별히 Instance Object 줄여서 Instance라고 명한다.

//클래스는 속성이 들어가지않은 청사진
class SomeThing{
  //세부사항은 생성자에서 넣자
  //argument1들은 속성(property/attribute)이다.
  constructor SomeThing(argument1, argument2, ...){
      ...고유 속성이 new 하면서 생성됨 initialized
  }
  //method 기능 function
  someFunction(){
      ...어떠한 구현
  }
  ...기능들 정의  구현 ~~민중의지팡이로 정의구현~~
}

5.2. OOP Basic Concepts

굉장히 중요한 이야기가 나온다. OOP를 제대로 이해하고 사용해야 제대로된 설계가 나올 수 있다. 나는 아직 이렇게 설계하고 해본적은 없고, 헤더부터 만들라던 전 팀장님의 이야기가 아마 이걸 기반으로 나온거라고 지금은 생각이 든다. 사설을 넣는다는건 꼭 봐라는 이야기.

5.3. Java에서의 주요특성 사용내용(JS와 비교)

  • Encapsulation(캡슐화): in Java private 사용하여 은닉화함. 클래스 내에서만 사용하거나 method에 private을 넘겨주는 형태로 내장되어있는 변수에 외부에서 직접 접근하지 못하도록 막을 수 있다. 반대의개념으로 public, 아니면 상수로 public static을 쓸수있다.
public static class A{
    private int encapsuleVal;
    public A(encapsuleVal){
        this.encapsuleVal = encapsuleVal;
    }

    public int getEncapsuleVal(){
        return this.encapsuleVal;
    }
}
  • Inheritance(상속): extents로 부모의 property나 method를 상속받아 사용할 수 있다. 알면 알수록 머리아프다.
  • Abstraction(추상화): abstract를 class앞에 부착하여 interface(명세 나중에 구현하세요란 말) 미리 값이 담겨있는 만들다가 만??class를 생성하여 class처럼 상속받아 사용할 수 있다. 예를들어 abstract class내 interface가 deleteInstance라면 단순하게 명세(구현안되있음)만 있고 상속받아 사용하는 class측에서 구현해주어야 한다.(아니면 에러뱉음^^)
  • Polymorphism(다형성): 하나의 원본을 가지고 여러가지 형태로 상속이나 추상화를 통해 구현할 수 있다.

5.4. 상기는 Java에서나 먹히던 말이고, JavaScript는 전혀 다르다.

5.4.1. Encapsulation

  • 데이터와 기능을 하나의 단위로 묶음.
  • 은닉(hiding), 구현은 숨기고 동작은 노출시킨다.
    • 내부 데이터나 내부 구현이 외부로 노출되지 않도록 만든다. -> 유지보수가 쉽다.
  • 느슨한 결합(Loose Coupling)에 유리하여 언제든 구현을 수정할 수 있다.
    • 코드 싱행 순서에 따라 절차적으로 코드를 작성하는것이 아닌, 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합하는 것을 의미한다.

엄격한 클래스의 속성의 직접적 접근을 막고, 설정을 하는 setter, getter를 철저히 나눈다.(변수 직접접근으로 인한 변조 막음.)

5.4.2. Abstraction

내부에서는 어떤일이 벌어지는지(복잡한지 뭔지)모르고, 노출되는 내부는 단순하게 만든다. interface를 정의하여 단순화 시킬 수 있다.

  1. 캡슐화 비슷해보이나, 캡슐화는 데이터변조를 막기위해 외부에서 직접접근을 못하게하는 은닉화가 초점이고,
  2. 추상화는 interface를 작성하여 명세만 볼 수 있도록하여 단순하게 이름만 정의(속성과 메서드를 진짜 정의만한것.)하는것이다.

5.4.3. Inheritance

부모자식말고 기본클래스 base class와 파생 클래스 derived class가 상속받는다고 한다. 같은코드가 여러번나오는건 비효율적이니 그룹핑하는거라고 볼 수 도 있다.

5.4.4. Polymorphism

똑같은 객체라도 여러가지 모양을 가질 수 있다. 붕어빵이 먹는거말고도 인형도 있고, 붕어빵이라고 불리는 사람도 있고, 붕어빵이라는 분식집부터 Poly(많은), Morph(형태)로 구현될 수 있다.

5.5. OOP의 장점

Encapsulation Reduce complexity + increase  
  코드가 복잡하지 않게 만들고 재사용성을 높인다.  
Abstraction Recude complexity + isolate impact of changes  
  코드를 복잡하지 않게 하고, 단순화된 사용으로 변화에대한 영향을 최소화한다.  
Inheritance Eliminate redundant code  
  불필요한 코드줄여 재사용성을 높인다.  
Polymorphism Refactor ugly if/else if statements  
  객체의 특성에 맞게 달리 작성이 가능하다.  

6. 객체 지향 차이점

TypeScript는 Java처럼 사용할 수 있게 해주지만, 지원하는 브라우저가 적다. private을 사용할 수 있다. JavaScript에서는 비슷한 형태로 클로저 모듈패턴을 사용하고, ES2019에서는 클래스/인스턴트 형태로 구현할때는 #이라는 키워드가 추가되었다.

추상화의 주요기능인 interface는 명세만 작성하여 추후 implement할 class에서 구현하는 것으로 대표적으로 API(Application Programming interface)처럼 외부 공개용으로 모듈처럼 작동할 때 좋다. 하지만 JavaScript에는 존재하지 않는다.

7. 주요 용어 보세영

prototype model의 blueprint 만들때 쓰는 original form  
constructor instance initialized될때 실행하는 constructor method  
this method 실행될 때 해당 scope마다 생성되는 고유한 실행 context(execution context) new 키워드로 instance를 생성했을 때 해당 instance가 this임.  

참조

MDN:JS/엄격모드
SS:Haddara/OOP introduction
YT:Mosh/OOP in JS