program story

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

inputbox 2020. 8. 22. 08:46
반응형

내가 할 수 없어야하는데 왜 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)();
    }
  }
}

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

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

  • 제안 : 생성자의 개인 속성
    • 문제 : 프로토 타입 함수에서 액세스 할 수 없음
  • 제안 : 생성자의 개인 메서드
    • 문제점 : 속성과 동일하며 프로토 타입에서 클래스 당 한 번 함수를 생성하는 성능 이점을 잃게됩니다. 대신 각 인스턴스에 대한 함수 사본을 만듭니다.
  • 제안 : 속성 액세스를 추상화하고 가시성을 강화하기 위해 상용구 추가
    • 문제 : 주요 성능 오버 헤드; TypeScript는 대규모 응용 프로그램을 위해 설계되었습니다.
  • 제안 : TypeScript는 이미 생성자 및 프로토 타입 메서드 정의를 클로저로 래핑합니다. 거기에 개인 메서드와 속성을 넣어
    • 그 클로저에 private 속성을 넣는 문제 : 그것들은 정적 변수가됩니다. 인스턴스 당 하나가 없습니다.
    • problems with putting private methods in that closure: they do not have access to this without some sort of workaround
  • Suggestion: automatically mangle the private variable names
    • counter arguments: that's a naming convention, not a language construct. Mangle it yourself
  • Suggestion: Annotate private methods with @private so minifiers that recognize that annotation can effectively minify the method names
    • No significant counter arguments to this one

Overall counter-arguments to adding visibility support in emitted code:

  • the problem is that JavaScript itself doesn't have visibility modifiers - this isn't TypeScript's problem
  • there is already an established pattern in the JavaScript community: prefix private properties and methods with an underscore, which says "proceed at your own risk"
  • when TypeScript designers said that truly private properties and methods aren't "possible", they meant "not possible under our design constraints", specifically:
    • The emitted JS is idiomatic
    • Boilerplate is minimal
    • No additional overhead compared to normal JS OOP

In TypeScript Private functions are only accessible inside the class. Like

enter image description here

And it will show an error when you try to access a private member. Here is the example:

enter image description here

Note: It will be fine with javascript and both function are accessible outside.


I realize this is an older discussion but it might still be useful to share my solution to the problem of the supposedly private variables and methods in a TypeScript "leaking" out into the public interface of the compiled JavaScript class.

To me this issue is purely cosmetic, i.e. it's all about the visual clutter when an instance variable is viewed in DevTools. My fix is to group private declarations together inside another class that is then instantiated in the main class and assigned to a private (but still publicly visible in JS) variable with a name like __ (double underscore).

Example:

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);

When the myClass instance is viewed in DevTools, instead of seeing all its "private" members intermixed with truly public ones (which can get very visually messy in properly refactored real-life code) you see them neatly grouped inside the collapsed __ property:

enter image description here

참고URL : https://stackoverflow.com/questions/12713659/why-can-i-access-typescript-private-members-when-i-shouldnt-be-able-to

반응형