본문 바로가기

개발/Web Front-End

클래스 분리 전 공부 사항

이번 미션에서 필요할 것 같은 부분만 정리

클래스 생성시 반드시 'new'를 붙여 생성합니다.

클래스는 파스칼케이스 (PascalCase)

constructor는 생성 및 초기화를 할 수 있습니다. 덧붙여 constructor 안에선 return문 써선 안됩니다.

여기서 static # 같은 글자를 baseball 미션 피어리뷰하면서 종종보고, 심지어 #은 이번 lotto미션에 등장하는데, 이것이 무엇이냐면, static은 정적메소드 즉 new 없이 사용 가능합니다. #은 그 유명한 private.

한줄씩으로 얘기하자면
정적 메서드는 특정 클래스 인스턴스가 아닌 클래스 '전체’에 필요한 기능을 만들 때 사용.
private는 함수도 클래스 내부에서만 사용할거면 사용. 외부에서도 호출할거면 public.

먼저 모든 Private 필드는 소속된 클래스에 고유한 스코프를 갖습니다.
예시를 들면

class Human {
  #age = 10;

  getAge() {
    return this.#age; 
  }
}

class Person extends Human {
  #age = 20;

  getFakeAge() {
    return this.#age;
  }
}

const p = new Person();
console.log(p.getAge()); // 20
console.log(p.getFakeAge());  // 20

당연히 p는 new로써 person 인스턴스가 만들어졌고,
getAge를 해도 getFakeAge를 해도 person의 인스턴스기에 20이 나와야한다고 생각했고 private이 없다면 이 상식이 맞았습니다. 허나, private이 존재한다면,

class Human {
  #age = 10;

  getAge() {
    return this.#age; 
  }
}

class Person extends Human {
  #age = 20;

  getFakeAge() {
    return this.#age;
  }
}

const p = new Person();
console.log(p.getAge()); // 10
console.log(p.getFakeAge());  // 20

다음과 같았습니다.
클로저 처럼 클래스의 메소드가 그 환경을 따로 기억하나 생각도 했지만, 정확하게는
private 속성은 기존처럼 인스턴스별로 독립적인 공간을 갖지만, 추가로 클래스 별로 독립적인 공간을 갖는다고 합니다. 쉽게 말하면 Human 클래스 스코프의 #age Person 클래스 스코프의 #age는 다르기에, getAge()가 실행될때는 Human #age에 접근하고 Person getFakeAge()가 실행될 때는 Person #age에 접근합니다.



static에 대해 조금 더 자세히 얘기하자면, 인스턴스로 호출할 수 없습니다.
즉 인스턴스 프로토타입 체인에 존재하지 않고 클래스 자체의 프로토타입 체인에 존재합니다.

class Foo {
  static doEating() {
    
  }

  static #raiseSpoon() {
    console.log("수저 들어");
    return true;
  }

  static #drinkWater() {
    console.log("물 마셔");
    return true;
  }

  goRestRoom() {
    console.log("화장실 가");
    return true;
  }
}

console.log(new Foo());


즉 static(정적 메서드)은 클래스 프로토타입에 저장되고 아니라면 인스턴스 프로토타입 메서드에 저장된다
덧붙여 static의 this는 클래스를 가리킵니다.

클래스에서 get 과 set은 해당 프로퍼티 접근 및 설정시 규약입니다.

이번 미션 피드백의 내용중 커밋 순서도 규칙이란 부분이 있는데,
여기서 클래스 필드란 constructor 안에 변수처럼 사용되는 this.xxx입니다.
최신 node에선 몸체안에 그냥 선언하고 초기화가 허용되긴합니다.
앞서 혼자 하던 개인 프로젝트들은 클래스내에 뭔가를 선언했기에 프로퍼티라 생각했습니다.
예를들어,

class foo(){

	prop = () => { ... }

}


이게 바로 클래스 필드에 함수를 할당한 것 이었습니다.
즉 이는 인스턴스의 프로퍼티가 됩니다. (권장되지 않는방법)


static # ?

static자체가 클래스 밖에서 사용되어서, new 연산자 사용 없이 편리하게 쓰고자 하는 것 아닌가?
굳이 private처리 할거면 밖에서 쓰지도 못하는데 왜 static을 붙일까?

해답은 고민에 비해 생각보다 간단했다.

class Foo {
  static doEating() {
    this.#raiseSpoon();
    this.#drinkWater();
    this.goRestRoom();
  }

  static #raiseSpoon() {
    console.log("수저 들어");
    return true;
  }

  static #drinkWater() {
    console.log("물 마셔");
    return true;
  }

  goRestRoom() {
    console.log("화장실 가");
    return true;
  }
}

쉽게 얘기하면 private 메소드와 동일한 목적인데, 프로토타입 체인 위치가 일반 메소드와 달라서 이다.

즉 인스턴스가 아닌 클래스 프로토타입에 저장되는 static으로 밖에서 사용할 메소드(doEating)에 들어갈 함수(raiseSpoon, drinkWater)가 클래스 내에서만 사용되고 있기에 private처리 까지 해주기 위해 사용된다.
조금 더 자세히 얘기 하자면 위에서 밝힌 바 대로 static은 클래스 프로토타입에 저장이되기에 static없는 goRestRoom메소드를 위에 doEating에 넣는다면 오류가 난다. goRestRoom메소드는 인스턴스 프로토타입에 저장되었기에 클래스 프로토타입에선 존재하지 않기 때문이다.

세줄 요약
만약 doEating()이 일반 메소드 라면, raiseSpoon()과 drinkwater()는 일반 메소드가 되고 (인스턴스 프로토타입)
만약 doEating()이 static 메소드 라면, raiseSpoon()과 drinkwater()는 static 메소드가 되고 (클래스 프로토타입)
raiseSpoon과 drinkWater는 밖에서 사용될 필요가 없기에 private처리. = > static # 사용.



참고자료 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields

'개발 > Web Front-End' 카테고리의 다른 글

URL과 URI  (0) 2022.09.10
SSR vs CSR , SEO문제 해결  (0) 2022.09.10
[클린코드 자바스크립트] 배열 및 객체  (0) 2022.08.31
Executive Context  (0) 2022.08.28
이벤트 버블링  (0) 2022.08.08