Вопрос по typescript, javascript – Почему я могу получить доступ к закрытым членам TypeScript, если не могу?
Я смотрю на реализацию закрытых членов в TypeScript, и я нахожу это немного запутанным. Intellisense не позволяет получить доступ к закрытому члену, но в чистом JavaScript это все есть. Это заставляет меня думать, что TS неправильно внедряет частных участников. Какие-нибудь мысли?
class Test{
private member: any = "private member";
}
alert(new Test().member);
Я понимаю, что это более старая дискуссия, но все же было бы полезно поделиться своим решением проблемы предположительно закрытых переменных и методов в TypeScript & quot; leaking & quot; в открытый интерфейс скомпилированного класса 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, вместо того, чтобы видеть все его "частные" члены, смешанные с действительно общедоступными (которые могут быть очень визуально запутанными в правильно переработанном реальном коде), вы видите их аккуратно сгруппированными внутри свернутого__
имущество:
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
Этот подход должен использоваться толькоSPARINGLY где это абсолютно необходимо. Например, если вам нужно временно кешировать пароль.
Использование этого шаблона сопряжено с затратами на производительность (не имеет отношения к 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)();
}
}
}
Спасибо Шону Фельдману за ссылку на официальное обсуждение этого вопроса - см.его ответ по ссылке.
Я прочитал дискуссию, с которой он связался, иhere's a summary of the key points:
- Suggestion: private properties in constructor
- problems: can't access from prototype functions
- Suggestion: private methods in constructor
- problems: same as with properties, plus you lose the performance benefit of creating a function once per class in the prototype; instead you create a copy of the function for each instance
- Suggestion: add boilerplate to abstract property access and enforce visibility
- problems: major performance overhead; TypeScript is designed for large applications
- Suggestion: TypeScript already wraps the constructor and prototype method definitions in a closure; put private methods and properties there
- problems with putting private properties in that closure: they become static variables; there is not one per instance
- 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
Как и при проверке типов, конфиденциальность членов обеспечивается только внутри компилятора.
Закрытое свойство реализовано как обычное свойство, и код вне класса не имеет доступа к нему.
Чтобы сделать что-то действительно закрытое внутри класса, оно не может быть членом класса, это была бы локальная переменная, созданная внутри области действия функции внутри кода, который создает объект. Это будет означать, что вы не можете получить к нему доступ как член класса, то есть с помощьюthis
ключевое слово.