티스토리 뷰

9.3 Static properties and methods

prototype이 아닌 클래스 자체적으로 메서드를 설정할 수 있다?(아마도 프로토 타입은 인스턴스가 생성될 때만 동작하는 것 같다.)

static 키워드를 붙여 만들 수 있고, 이를 정적 메서드라고 부른다. 어떤 객체가 아닌 클래스 전체에 활용될 수 있는 함수를 구현하고자 할 때 쓰인다.

아래 Article 간의 비교를 위한 메서드가 그 예시다.

class Article {
  constructor(title, date) {
    this.title = title;
    this.date = date;
  }

  static compare(articleA, articleB) {
    return articleA.date - articleB.date;
  }
}

// 사용법
let articles = [
  new Article("HTML", new Date(2019, 1, 1)),
  new Article("CSS", new Date(2019, 0, 1)),
  new Article("JavaScript", new Date(2019, 11, 1))
];

articles.sort(Article.compare);

alert( articles[0].title ); // CSS

아래는 Article을 생성할 때, 팩토리 메서드 패턴을 위해 static 메서드를 활용한 경우다. 

class Article {
  constructor(title, date) {
    this.title = title;
    this.date = date;
  }

  static createTodays() {
    // this는 Article입니다.
    return new this("Today's digest", new Date());
  }
}

let article = Article.createTodays();

alert( article.title ); // Today's digest

static properties

말 그대로 static이 붙은 속성을 의미한다. 

class Article {
  static publisher = "Ilya Kantor";
}

alert( Article.publisher ); // Ilya Kantor

// ----------------

Article.publisher = "Ilya Kantor";

Inheritance of static properties and methods

정적 프로퍼티와 메서드도 상속이 된다.

class Animal {
  static planet = "지구";

  constructor(name, speed) {
    this.speed = speed;
    this.name = name;
  }

  run(speed = 0) {
    this.speed += speed;
    alert(`${this.name}가 속도 ${this.speed}로 달립니다.`);
  }

  static compare(animalA, animalB) {
    return animalA.speed - animalB.speed;
  }

}

// Animal을 상속받음
class Rabbit extends Animal {
  hide() {
    alert(`${this.name}가 숨었습니다!`);
  }
}

let rabbits = [
  new Rabbit("흰 토끼", 10),
  new Rabbit("검은 토끼", 5)
];

rabbits.sort(Rabbit.compare);

rabbits[0].run(); // 검은 토끼가 속도 5로 달립니다.

alert(Rabbit.planet); // 지구

Java에서 static 키워드가 붙은 요소에 대해 클래스 영역에 따로 저장되기 때문에, 상속과는 별개로 직접 접근이 가능한 걸로 알고 있는데 javascript는 상속에 초점이 맞춰져 있는 느낌이다. 이 부분은 다시 살펴봐야겠다.

9.4 Private and Protected properties and methods

이번 장은 Java에서는 접근제어자와 같은 개념인데, 추상적인 설명은 제외하고 실제 언어에서 어떻게 필드의 접근을 제어하는지만 살펴보자. 

Protecting "waterAmount"

class CoffeeMachine {
  waterAmount = 0; // 물통에 차 있는 물의 양

  constructor(power) {
    this.power = power;
    alert( `전력량이 ${power}인 커피머신을 만듭니다.` );
  }

}

// 커피 머신 생성
let coffeeMachine = new CoffeeMachine(100);

// 물 추가
coffeeMachine.waterAmount = 200;

waterAmount를 내부에서만 다룰 수 있는 속성으로 취급하고 싶을 때, 이를 proected로 바꾸면 된다. javascript에서는 컨벤션으로 밑줄 '_'을 붙여 proteced를 표현한다. (javascript에서 강제하는 것이 아니다.)

class CoffeeMachine {
  _waterAmount = 0;

  set waterAmount(value) {
    if (value < 0) throw new Error("물의 양은 음수가 될 수 없습니다.");
    this._waterAmount = value;
  }

  get waterAmount() {
    return this._waterAmount;
  }

  constructor(power) {
    this._power = power;
  }

}

// 커피 머신 생성
let coffeeMachine = new CoffeeMachine(100);

// 물 추가
coffeeMachine.waterAmount = -10; // Error: 물의 양은 음수가 될 수 없습니다.

read-only "power"

경우에 따라, getter 메서드만 구현하여 읽기 전용으로 만들 수도 있겠다.

class CoffeeMachine {
  // ...

  constructor(power) {
    this._power = power;
  }

  get power() {
    return this._power;
  }

}

// 커피 머신 생성
let coffeeMachine = new CoffeeMachine(100);

alert(`전력량이 ${coffeeMachine.power}인 커피머신을 만듭니다.`); // 전력량이 100인 커피머신을 만듭니다.

coffeeMachine.power = 25; // Error (setter 없음)

// --------------------

// 아래처럼 get, set 키워드를 쓰지 않고 메서드를 만들 수도 있다.
class CoffeeMachine {
  _waterAmount = 0;

  setWaterAmount(value) {
    if (value < 0) throw new Error("물의 양은 음수가 될 수 없습니다.");
    this._waterAmount = value;
  }

  getWaterAmount() {
    return this._waterAmount;
  }
}

new CoffeeMachine().setWaterAmount(100);

private "#waterLimit"

javascript에서 클래스 내부에서만 접근할 수 있도록 강제하는 문법이다.

class CoffeeMachine {
  #waterLimit = 200;

  #checkWater(value) {
    if (value < 0) throw new Error("물의 양은 음수가 될 수 없습니다.");
    if (value > this.#waterLimit) throw new Error("물이 용량을 초과합니다.");
  }

}

let coffeeMachine = new CoffeeMachine();

// 클래스 외부에서 private에 접근할 수 없음
coffeeMachine.#checkWater(); // Error
coffeeMachine.#waterLimit = 1000; // Error

private으로 waterAmount 속성을 가지고 있어도 public waterAmount 속성을 가질 수 있다.

 

상속받은 클래스에서는 접근이 안된다. 또한, 내부에서도 this[name] 형식으로 접근이 되지 않는다. 

class MegaCoffeeMachine extends CoffeeMachine {
  method() {
    alert( this.#waterAmount ); // Error: CoffeeMachine을 통해서만 접근할 수 있습니다.
  }
}

// --------

class User {
  ...
  sayHi() {
    let fieldName = "name";
    alert(`Hello, ${this[fieldName]}`);
  }
}
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday