[javascript] 내가 할 수 없어야하는데 왜 TypeScript 개인 멤버에 액세스 할 수 있습니까?

TypeScript에서 private 멤버의 구현을보고 있는데 약간 혼란 스럽습니다. Intellisense는 개인 멤버에 액세스하는 것을 허용하지 않지만 순수 JavaScript에서는 모든 것이 있습니다. 이것은 TS가 개인 구성원을 올바르게 구현하지 않는다고 생각합니다. 이견있는 사람?

class Test{
  private member: any = "private member";
}
alert(new Test().member);



답변

유형 검사와 마찬가지로 멤버의 개인 정보는 컴파일러 내에서만 적용됩니다.

개인 속성은 일반 속성으로 구현되며 클래스 외부의 코드는 액세스 할 수 없습니다.

클래스 내에서 진정으로 비공개로 만들려면 클래스의 멤버가 될 수 없으며 객체를 생성하는 코드 내 함수 범위 내에 생성 된 지역 변수가됩니다. 즉, this키워드를 사용하여 클래스의 구성원처럼 액세스 할 수 없습니다 .


답변

JavaScript는 개인 변수를 지원합니다.

function MyClass() {
    var myPrivateVar = 3;

    this.doSomething = function() {
        return myPrivateVar++;        
    }
}

TypeScript에서 이것은 다음과 같이 표현됩니다.

class MyClass {

    doSomething: () => number;

    constructor() {
        var myPrivateVar = 3;

        this.doSomething = function () {
            return myPrivateVar++;
        }
    }
}

편집하다

이 방법은에만 사용해야 아껴서 이 절대적으로 필요한 곳. 예를 들어 암호를 임시로 캐시해야하는 경우입니다.

이 패턴 (Javascript 또는 Typescript와 무관)을 사용하면 성능 비용이 발생하며 절대적으로 필요한 경우에만 사용해야합니다.


답변

WeakMap 에 대한 지원 이 더 널리 사용 가능 해지면 여기 예제 # 3에 자세히 설명 된 흥미로운 기술이 있습니다 .

개인 데이터를 허용하고 인스턴스 메서드 만이 아닌 프로토 타입 메서드에서 데이터에 액세스 할 수 있도록함으로써 Jason Evans 예제의 성능 비용을 피할 수 있습니다.

링크 된 MDN WeakMap 페이지에는 Chrome 36, Firefox 6.0, IE 11, Opera 23 및 Safari 7.1에서의 브라우저 지원이 나열됩니다.

let _counter = new WeakMap();
let _action = new WeakMap();
class Countdown {
  constructor(counter, action) {
    _counter.set(this, counter);
    _action.set(this, action);
  }
  decrement() {
    let counter = _counter.get(this);
    if (counter < 1) return;
    counter--;
    _counter.set(this, counter);
    if (counter === 0) {
      _action.get(this)();
    }
  }
}


답변

TypeScript 3.8이 출시 될 예정이므로 포함하는 클래스 외부에서 액세스하거나 감지 할 수없는 비공개 필드를 선언 할 수 있습니다 .

class Person {
    #name: string

    constructor(name: string) {
        this.#name = name;
    }

    greet() {
        console.log(`Hello, my name is ${this.#name}!`);
    }
}

let jeremy = new Person("Jeremy Bearimy");

jeremy.#name
//     ~~~~~
// Property '#name' is not accessible outside class 'Person'
// because it has a private identifier.

개인 필드는 #문자로 시작 합니다.

이 비공개 필드는 private키워드 로 표시된 필드와 다른 것입니다.

Ref. https://devblogs.microsoft.com/typescript/announcing-typescript-3-8-beta/


답변

이 문제에 대한 공식 토론 링크에 대한 Sean Feldman에게 감사드립니다. 링크에 대한 그의 답변 을 참조하십시오 .

그가 링크 한 토론을 읽었으며 여기에 주요 요점에 대한 요약이 있습니다.

  • 제안 : 생성자의 개인 속성
    • 문제 : 프로토 타입 함수에서 액세스 할 수 없음
  • 제안 : 생성자의 개인 메서드
    • 문제점 : 속성과 동일하며 프로토 타입에서 클래스 당 한 번 함수를 생성하는 성능 이점을 잃게됩니다. 대신 각 인스턴스에 대한 함수 사본을 만듭니다.
  • 제안 : 속성 액세스를 추상화하고 가시성을 강화하기 위해 상용구 추가
    • 문제 : 주요 성능 오버 헤드; TypeScript는 대규모 응용 프로그램을 위해 설계되었습니다.
  • 제안 : TypeScript는 이미 생성자 및 프로토 타입 메서드 정의를 클로저로 래핑합니다. 거기에 개인 메서드와 속성을 넣어
    • 그 클로저에 private 속성을 넣는 문제 : 그것들은 정적 변수가됩니다. 인스턴스 당 하나가 없습니다.
    • 해당 클로저에 개인 메서드를 넣는 데 문제 가 있습니다. this일종의 해결 방법 없이는 액세스 할 수 없습니다.
  • 제안 : 개인 변수 이름을 자동으로 변경
    • 반대 인수 : 이는 언어 구조가 아닌 명명 규칙입니다. 직접 엉망으로 만드십시오.
  • 제안 : 주석 @private이 메서드 이름을 효과적으로 축소 할 수 있음을 인식하는 축소자를 사용하여 비공개 메서드에 주석을 추가 합니다.
    • 이것에 대한 중요한 반론이 없습니다.

내 보낸 코드에서 가시성 지원 추가에 대한 전반적인 반론 :

  • 문제는 JavaScript 자체에 가시성 수정자가 없다는 것입니다. 이것은 TypeScript의 문제가 아닙니다.
  • JavaScript 커뮤니티에는 이미 확립 된 패턴이 있습니다. “자신의 책임하에 진행하십시오”라는 밑줄이있는 개인 속성 및 메서드 접두사
  • TypeScript 디자이너가 진정으로 사적인 속성과 메서드가 “가능하지 않다”고 말했을 때, 그들은 “우리의 디자인 제약 하에서 가능하지 않다”를 의미합니다. 특히 :
    • 내 보낸 JS는 관용적입니다.
    • 보일러 플레이트가 최소화 됨
    • 일반 JS OOP에 비해 추가 오버 헤드 없음

답변

TypeScript에서 Private 함수는 클래스 내에서만 액세스 할 수 있습니다. 처럼

여기에 이미지 설명 입력

그리고 비공개 회원에 접근을 시도하면 오류가 표시됩니다. 다음은 그 예입니다.

여기에 이미지 설명 입력

참고 : 자바 스크립트에서는 문제가 없으며 두 기능 모두 외부에서 액세스 할 수 있습니다.


답변

나는 이것이 오래된 논의라는 것을 알고 있지만 컴파일 된 JavaScript 클래스의 공용 인터페이스로 “누출”되는 TypeScript의 개인 변수 및 메서드 문제에 대한 내 솔루션을 공유하는 것이 여전히 유용 할 수 있습니다.

나에게이 문제는 순전히 외형적인 문제입니다. 즉, DevTools에서 인스턴스 변수를 볼 때 시각적 인 혼란에 관한 것입니다. 내 수정 사항은 다른 클래스 내에서 개인 선언을 그룹화 한 다음 기본 클래스에서 인스턴스화하고 (이중 밑줄) private과 같은 이름을 가진 (JS에서는 여전히 공개적으로 볼 수 있음) 변수에 할당하는 것 __입니다.

예:

class Privates {
    readonly DEFAULT_MULTIPLIER = 2;
    foo: number;
    bar: number;

    someMethod = (multiplier: number = this.DEFAULT_MULTIPLIER) => {
        return multiplier * (this.foo + this.bar);
    }

    private _class: MyClass;

    constructor(_class: MyClass) {
        this._class = _class;
    }
}

export class MyClass {
    private __: Privates = new Privates(this);

    constructor(foo: number, bar: number, baz: number) {
        // assign private property values...
        this.__.foo = foo;
        this.__.bar = bar;

        // assign public property values...
        this.baz = baz;
    }

    baz: number;

    print = () => {
        console.log(`foo=${this.__.foo}, bar=${this.__.bar}`);
        console.log(`someMethod returns ${this.__.someMethod()}`);
    }
}

let myClass = new MyClass(1, 2, 3);

myClass인스턴스를 DevTools에서 볼 때 모든 “비공개”멤버가 진정한 공개 멤버와 혼합 된 것을 보는 대신 (적절하게 리팩토링 된 실제 코드에서 시각적으로 매우 지저분해질 수 있음) 축소 된 __속성 내에서 깔끔하게 그룹화되는 것을 볼 수 있습니다.

여기에 이미지 설명 입력