javascript class와 private 속성

2022-09-12

과거 javascript는 객체에 private한 속성을 만들 수 없었다.

  • 컨밴션을 정해 외부에서 사용하지 않도록 했다.
    (e.g. _언더바가 prefix로 붙으면 외부에서 접근하지 않는다. 하지만 실제론 접근 가능.)
  • 그러나 근본적으로 private한 속성을 만드는 것이 아닌 치명적인 단점이 있다.
function SomeConstructor() {
  this._privateProp = "dont touch this";
  this.publicProp = "you can touch this";
}

근본적으로 접근이 불가능한 private 속성을 만들기

  • 클로저를 사용한다.
function SomeModule() {
  const privateProp = 'dont touch this';
  const publicProp = 'you can touch this';
 
  _doSomethingWithPrivateProp = () => { ... }
 
  const publicMethod = () => {
    _doSomethingWithPrivateProp();
    // ...
  }
 
  return {
    publicProp,
    publicMethod
  }
}
  • 효과적으로 데이터와 메서드를 숨기는데 유용하다.
  • 생성자의 인스턴스 별로 private한 속성을 만들어야하는 상황에서는 적절치 않다.

드디어 정식으로 private속성을 만들수 있다.

  • private와 같은 키워드 대신, prefix로 # 를 사용한다.
  • 속성 명 앞에 # 이 붙으면 private한 필드로 동작한다.
  • # 없이 동작할 수 없다.
class Human {
  #age = 10;
}
 
const person = new Human();
class Human {
  #age = 10;
 
  getAge() {
    return this.age;
    // Error TS2551: Property 'age' does not exist on type 'Human'.
    // Did you mean '#age'?
  }
}
  • 반드시 선언을 통해서만 만들 수 있고 동적으로 추가할 수 없다.
  • 메서드를 선언할때는 사용할 수 없다.
  • 외부의 게터를 통해 private 속성에 접근할 수 있다.
class Human {
  #age = 10;
 
  getAge() {
    return this.#age;
  }
}
 
const person = new Human();
 
console.log(person.getAge()); // 10

모든 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());
console.log(p.getFakeAge());
  • public 속성이라면 this 컨텍스트에는 age 속성이 하나기 때문에 age의 값이 20이다.
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
  • 기존처럼 인스턴스별로 독립적인 공간을 갖지만, 추가로 클래스 별로 독립적인 공간을 갖는 것이다.
  • Human 클래스 스코프의 #age와 Person 클래스 스코프의 #age는 다르다.
  • 그러므로 Human 클래스에 속한 getAge()가 실행될때는 Human의 #age에 접근하고 Person의 getFakeAge()가 실행될 때는 Person의 #age에 접근한다.

JavaScript # vs TypeScript private

  • runtime vs compile
  • TypeScript private는 컴파일 이후에 런타임에 적용되지 않는 문법