자바스크립트 클래스 이해하다가 머리터지기 🤯 (feat. 필드와 컨스트럭터)

REASON·2022년 11월 9일
0

STUDY

목록 보기
113/127

객체지향에서 내부 인터페이스외부 인터페이스를 구분해야 한다.
OOP 말로만 들었지 직접 공부해보게 될 줄은 몰랐다. 특히 그것도 자바스크립트에서..

내부 인터페이스

동일한 클래스의 다른 메서드에서는 접근할 수 있지만, 해당 클래스 외부에서는 접근할 수 없는 프로퍼티와 메서드를 의미한다.

외부 인터페이스

클래스 밖에서도 접근할 수 있는 프로퍼티와 메서드를 의미한다.

모던 자바스크립트 튜토리얼에서는 내부 인터페이스와 외부 인터페이스에 대한 설명으로 커피머신을 예시로 들고 있었는데 커피머신을 떠올려보면 사용자는 버튼 하나를 눌러서 커피 머신을 동작시키는 것처럼 매우 간단하게 사용할 수 있지만, 내부에서는 복잡한 구조와 과정(?)을 통해 커피 머신이 동작한다는 내용이었다.

즉, 내부 인터페이스에서는 머신이 동작하는데 필요하지만 실제 사용자가 알 필요는 없는 것들을 다루는 것이고 외부 인터페이스에서는 사용자가 딱 필요한 것만 할 수 있도록 보여준다로 이해할 수 있었다.

그러므로 사용자는 외부 인터페이스만 알고 있어도 무언가 사용하는데 지장이 없다.

그렇다면 이게 private, protected와 무슨 관련이 있는 걸까?

실생활 예시만 들어보면 너무 당연하게 생각해왔던 내용들이었기에 이해하는데 어렵지 않다.
커피 뽑아먹어야지~ 하면 당연히 동작하는 버튼부터 찾지 내부는 무슨 구조이고..
이게 물이 어떻게 나오고.. 이런 디테일한 것까지 사용자는 몰라도 상관 없기 때문이다.
해당 부분을 프로그래밍적으로 이해하기 위해선 접근 제어자에 대해 알 필요가 있었다.

접근 제어자

public : 어디서든지 접근할 수 있다.

class에서 일반적으로 사용되는 프로퍼티, 메서드가 public에 해당된다.

private : 클래스 내부에서만 접근할 수 있다.

클래스 내부에서만 접근 가능하기 때문에 내부 인터페이스를 구성할 때 사용된다.

protected : 자바스크립트에서 지원되지 않는다.

다른 언어에서는 지원되지만 자바스크립트에서는 protected는 지원되지 않는다.
protected는 private와 비슷하지만 자손 클래스에서 접근이 가능한 키워드이다.
자바스크립트에도 protected가 있는건가 ? 했는데 없다고 한다. 비슷하게 흉내를 내서 사용하는 경우가 많다는 것을 보니.. 그래도 protected가 어떤 의미인지 정도는 짚고 넘어가는 게 좋을 것 같다.

public이야 워낙 기본적인거라 어렵지 않지만, 자바와 같이 객체지향언어는 잘 모르기 때문에 접근제어자는 아직도 낯설다..ㅎㅎ private과 protected에 대해서는 긴가민가해서 예시를 통해 자세히 이해해보는게 좋을 것 같다.

class CoffeeMachine {
  waterAmount = 0;

  constructor(power){
    this.power = power;
    console.log(`전력량이 ${power}인 커피머신 생성`);
  }
}
const coffeeMachine = new CoffeeMachine(100);
// 전력량이 100인 커피머신 생성

외부 IDE에서 waterAmount를 Class Field로 선언하니 classProperties 지원하지 않는다고 에러 메시지를 띄우길래 구글 콘솔을 사용했다.. 콘솔은 불편하니 다른 IDE를 찾아서 하는걸로..ㅋㅋ

MDN을 찾아보니 아직 실험기능?같은 건지 사용은 할 수 있지만 babel을 사용하라고 적혀있었다.
아마 최신 브라우저들만 지원하는 기능인가보다.

저 문법을 보니 갑자기 드는 생각이 있다.
private을 살펴보기 전에 잠시 먼저 해결하고 싶은 궁금증이 생겼다.

public field로 선언하는 것과 constructor에 선언하는 것의 차이점은 무엇일까?

컨스트럭터에 넣은 것은 인스턴스 생성 시 하나씩 부여(?) 제공(?)..ㅋㅋㅋ 해주는 걸로 알고 있는데
그러면 퍼블릭 필드는 모든 인스턴스가 공유해서 쓸 수 있는게 맞나? 😨 음?
슬슬 머리가 아파오기 시작한다..ㅋㅋㅋㅋ
어쨌든 어디다 물어보기 전에 직접 검증해보기로 했다. (자바 공부는 아닌데 자바 선생님 찾아요..)
public static fieldpublic field의 차이가 살짝 헷갈리기도 했기 때문에 직접 쳐보고 이해하는게 가장 좋을 것 같았다.

class CoffeeMachine {
  waterAmount = 0;
  
  constructor(power){
    this.power = power;
    console.log(`전력량이 ${power}인 커피머신`);
  }
}

const coffeeMachine1 = new CoffeeMachine(100);
const coffeeMachine2 = new CoffeeMachine(50);
console.log(coffeeMachine1);
console.log(coffeeMachine2);

커피머신1과 2를 만들고 해당 인스턴스를 확인해보았다.
컨스트럭터는 power만 받고 있기 때문에 각각 100, 50의 값을 가지고 있는 것을 확인할 수 있었다.
여기서 컨스트럭터에서 전달하지 않은 값인 waterAmount가 각각의 인스턴스 속성으로 부여되어 있는 것을 볼 수 있는데, 클래스에서 퍼블릭 필드로 선언한 waterAmount가 가지고 있던 0이 커피머신 클래스로 만든 인스턴스의 속성값으로 들어가 있는 부분을 확인할 수 있었다.
즉, 클래스에서 필드로 선언했던 waterAmount는 컨스트럭터에 정의하지 않았음에도 인스턴스를 생성할 때 인스턴스의 속성 값으로 정의된다는 것이다.

그렇다면, 커피머신1과 커피머신2의 waterAmount 값을 변경시키면 서로 영향을 미칠까?

coffeeMachine1.waterAmount = 20;
console.log(coffeeMachine1);
console.log(coffeeMachine2);

우선 커피머신1의 waterAmount 값을 20으로 변경시켜보았다.

커피머신1의 waterAmount 값만 변경되었다.
이로 인해 커피머신1과 2가 커피머신 클래스의 퍼블릭 필드인 waterAmount를 공유하는 것은 아닌 것을 확인할 수 있었다.

이번엔 커피머신 클래스의 waterAmountstatic으로 선언해보자.

class CoffeeMachine {
  static waterAmount = 0;
  
  constructor(power){
    this.power = power;
    console.log(`전력량이 ${power}인 커피머신`);
  }
}

const coffeeMachine1 = new CoffeeMachine(100);
const coffeeMachine2 = new CoffeeMachine(50);
console.log(coffeeMachine1);
console.log(coffeeMachine2);

static으로 선언한 waterAmount는 앞서 퍼블릭 필드로 선언했을 때와 달리
인스턴스가 직접 waterAmount를 가지고 있지 않은 것을 확인할 수 있었다.
즉, 클래스에서만 가지고 있고 싶다면 static 필드로 선언하면 되는 것 같다.
접근할 때도 인스턴스.waterAmount로 접근하지 않고 static이기 때문에 클래스명.waterAmount로 접근해야 한다.

이쯤되니 의문이 생긴다.

자바스크립트에서 클래스를 쓸 일이 없었기에 고민해본적이 없었다...
그러면 생성자로 만드는 것과 public field로 만드는게 무슨 차이인가..?
관련 자료를 찾으려니 역시나 자바스크립트 대신 역시 자바 자료가 우르르 쏟아져나온다.
나.. 이러다.. 자바해야될 것 같기도..

생성 시점에 모두 같은 값을 갖고 싶다면 public 필드로!
인스턴스 생성과 동시에 초기화시키고 싶다면 컨스트럭터로!
라고 이해했다.

초기값이 지정되지 않은 필드는 자동으로 기본 초기값으로 설정된다.

자바스크립트에서는 초기값이 지정되지 않은 필드는 undefined 값을 가진다.

생성 시점에 모두 같은 값을 가지고 싶다면 필드로 선언하면 된다고 했는데
필드로도 선언하고 컨스트럭터에서 초기화 시키는건 뭘까?

그냥 컨스트럭터에서 선언해서 쓰면 안되는걸까..? 하는 두번째 의문이 생겼다.
정말 파고들면 파고들수록 너무 어렵다 클래스...ㅠㅠ

class CoffeeMachine {
  waterAmount = 0;
  
  constructor(power, waterAmount){
    this.power = power;
    this.waterAmount = waterAmount;
  }
}

const coffeeMachine1 = new CoffeeMachine(100);
console.log('1번 커피머신 :', coffeeMachine1);


const coffeeMachine2 = new CoffeeMachine(100, 10);
console.log('2번 커피머신 :' ,coffeeMachine2);

개인적으로 코드로 작성해보고 이해한 바를 정리해보자면

필드로 선언한 값을 기본 초기값으로 가지지만,
다른 값으로 초기화하고 싶은 경우 생성자에서 초기값을 주도록 만들 수 있다.

즉, 필드로 선언한 경우 생성시 모든 인스턴스가 같은 초기값을 갖게 되기 때문에
별도로 설정하고 싶을 때 컨스트럭터에서 초기화 할 수 있도록 선택지(?)를 줄 수 있는 것이다.
일단 인스턴스부터 만들고 변경시켜도 되긴하지만, 같은 값으로 초기화 시키고 싶다면 field로 주면 된다고 이해했다.

그렇기 때문에 이 코드는 모든 커피머신 인스턴스가 waterAmount 값을 0을 갖도록 만들겠다는 의미가 된다. 각 커피머신마다 전력 소비는 차이가 있을 수 있으므로 power를 constructor로 선언했다고 볼 수 있을 것 같다.

어.. 여기까진 다 좋은데 정말 궁금했던 부분은 아직 해소하지 못했다.
필드에서도 선언하고 컨스트럭터에서도 선언한 코드는 도대체 뭘까?

1번 머신에는 waterAmount 초기값을 주고 2번 머신에는 주지 않아보았다.
처음 예상했을 때는 2번 머신은 0을 초기값으로 가질 줄 알았는데 undefined가 되어있었다. 🤯
내가 잘못 이해한걸까.

검색해서 찾아보니 외부 값을 받아서 초기화 해야 하는 경우에 생성자를 사용하고,
외부에서 값을 받아서 초기화 할 필요가 없는 경우에는 생성자 또는 클래스 필드 라는 선택지가 있다고 한다. (아 그렇구나..!)

자바에서는 생성자를 여러개 만들 수 있다고 하는데 자바스크립트는 constructor를 1개밖에 가질 수 없다. 그렇기에 자바 자료를 보면서 공부했더니 약간 더 헷갈리는 것 같다. ㅋㅋㅋ

private 공부하러 왔다가 생성자와 필드 지옥에 빠져서 결국 프라이빗은 구경도 못했다.
내일 이어서 클래스를 부숴봐야겠다.


참고 자료
모던 자바스크립트 튜토리얼
MDN 클래스
자바의 필드와 생성자
[JavaScript] 자바스크립트 클래스 필드와 이벤트 핸들러

0개의 댓글