Машинопись частных членов


Я смотрю на реализацию частных членов в TypeScript, и я нахожу это немного запутанным. Intellisense не позволяет получить доступ к закрытому члену, но в чистом JavaScript все это есть. Это заставляет меня думать, что TS не реализует частные члены правильно. Есть мысли?

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

6 ответов:

как и при проверке типов, конфиденциальность членов применяется только в компиляторе.

частное свойство реализуется как обычное свойство, и код вне класса не имеет доступа к нему.

чтобы сделать что-то действительно частным внутри класса, он не может быть членом класса, это будет локальная переменная, созданная внутри области функции внутри кода, который создает объект. Это будет означать, что вы не можете получить доступ к нему как член класс, т. е. с помощью 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++;
        }
    }
}

EDIT

этот подход следует использовать только умеренно где это абсолютно необходимо. Например, если вам нужно временно кэшировать пароль.

есть затраты на производительность при использовании этого шаблона (не имеет отношения к Javascript или Typescript) и должен использоваться только там, где абсолютно необходимый.

один раз поддержка WeakMap более широко доступен есть интересная методика подробно описанная в Примере #3 здесь.

Он позволяет использовать личные данные и позволяет избежать затрат на производительность примера Джейсона Эванса, позволяя получать данные из методов прототипа, а не только из методов экземпляра.

на связанной странице 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 предназначен для большие приложения
  • предложение: TypeScript уже обертывает определения метода конструктора и прототипа в закрытии; поместите туда частные методы и свойства
    • проблемы с помещением частных свойств в это закрытие: они становятся статическими переменными; нет ни одного на экземпляр
    • проблемы с помещением частных методов в это закрытие: они не имеют доступа к this без какого-то обходного пути
  • предложение: автоматически калечить имена частных переменных
    • контр аргументы: это соглашение об именовании, а не языковая конструкция. Покалечить его самостоятельно
  • предложение: комментировать частные методы с @private таким образом, минификаторы, которые распознают эту аннотацию, могут эффективно минимизировать метод имена
    • никаких существенных контраргументов к этому

общие контраргументы для добавления поддержки видимости в исходящий код:

  • проблема в том, что сам JavaScript не имеет модификаторов видимости-это не проблема TypeScript
  • в сообществе JavaScript уже существует установленный шаблон: префикс частных свойств и методов с подчеркиванием, который говорит "действуйте на свой страх и риск"
  • когда дизайнеры TypeScript сказали, что действительно частные свойства и методы "невозможны", они имели в виду "невозможно при наших ограничениях дизайна", в частности:
    • испускаемый JS является идиоматическим
    • шаблон минимален
    • никаких дополнительных накладных расходов по сравнению с обычным JS ООП

в TypeScript частные функции доступны только внутри класса. Как

enter image description here

и он покажет ошибку, когда вы пытаетесь получить доступ к частному члену. Вот пример:

enter image description here

Примечание: это будет хорошо с JavaScript и обе функции доступны внешний.

Я понимаю, что это более старая дискуссия, но все же было бы полезно поделиться своим решением проблемы якобы частных переменных и методов в типовом тексте, "просачивающемся" в публичный интерфейс скомпилированного класса JavaScript.

для меня эта проблема является чисто косметической, т. е. все дело в визуальном беспорядке, когда переменная экземпляра просматривается в 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, вместо того, чтобы видеть все его "частные" члены, смешанные с действительно публичными (которые могут быть очень визуально грязными в правильно рефакторингованном реальном коде), вы видите их аккуратно сгруппированными внутри свернутого __ свойство:

enter image description here