为什么我不能访问TypeScript私有成员?

JavaScript TypeScript

神无

2020-05-28

我正在研究TypeScript中私有成员的实现,但我感到有些困惑。Intellisense不允许访问私有成员,但是在纯JavaScript中,仅此而已。这使我认为TS无法正确实现私有成员。有什么想法吗?

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

第4203篇《为什么我不能访问TypeScript私有成员?》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

6个回答
Gil伽罗小宇宙 2020.05.28

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.

对我来说,这个问题纯粹是表面上的问题,即与在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中查看实例时,您没有看到它们的所有“私有”成员与真正的公共成员混合在一起(在正确重构的真实生活代码中,它们在视觉上会非常混乱),而是看到它们被整齐地分组在折叠__属性内:

在此处输入图片说明

王者一打九 2020.05.28

一旦支持WeakMap是更广泛的应用存在例如#3详述了一个有趣的技术在这里

It allows for private data AND avoids the performance costs of Jason Evans example by allowing the data to be accessible from prototype methods instead of only instance methods.

The linked MDN WeakMap page lists browser support at Chrome 36, Firefox 6.0, IE 11, Opera 23, and 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)();
    }
  }
}
阿飞 2020.05.28

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无关),仅在绝对必要的情况下使用。

猴子 2020.05.28

感谢肖恩·费尔德曼(Sean Feldman)提供的关于此问题的正式讨论的链接-请参阅他的回答

我阅读了他链接的讨论,这是关键点的摘要:

  • 建议:构造函数中的私有属性
    • 问题:无法从原型函数访问
  • 建议:构造函数中的私有方法
    • 问题:与属性相同,而且您失去了在原型中为每个类创建一次函数的性能优势;而是为每个实例创建函数的副本
  • 建议:添加样板以抽象属性访问并增强可见性
    • 问题:主要的性能开销;TypeScript专为大型应用程序而设计
  • 建议: TypeScript已经将构造函数和原型方法定义包装在一个闭包中。将私有方法和属性放在那里
    • 将私有属性放在该闭包中的问题:它们成为静态变量;每个实例没有一个
    • 将私有方法放入该闭包中的问题:this没有某种变通办法,它们将无法访问
  • 建议:自动修改私有变量名称
    • 反论点:这是命名约定,不是语言构造。自己弄乱
  • 建议:使用@private使注释器识别私有注释可以有效地缩小方法名称的注释器来 注释私有方法
    • 对此没有重大反驳

在发出的代码中增加可见性支持的总体反论点:

  • 问题是JavaScript本身没有可见性修饰符-这不是TypeScript的问题
  • JavaScript社区中已经建立了一个模式:在私有属性和方法前加下划线,表示“后果自负”。
  • 当TypeScript设计师说真正的私有属性和方法不是“可能的”时,他们的意思是“在我们的设计约束下是不可能的”,特别是:
    • 发出的JS是惯用的
    • 样板最小
    • 与普通JS OOP相比,没有额外的开销
神无 2020.05.28

在TypeScript中,私有函数只能在类内部访问。喜欢

在此处输入图片说明

当您尝试访问私有成员时,它将显示错误。这是示例:

在此处输入图片说明

注意:使用javascript很好,并且两个函数都可以在外部访问。

启人 2020.05.28

就像类型检查一样,成员的隐私仅在编译器中强制执行。

私有属性实现为常规属性,并且不允许类外部的代码对其进行访问。

为了使某些东西真正成为类的私有对象,它不能成为该类的成员,而应是在创建对象的代码内的函数作用域内创建的局部变量。那将意味着您不能像类的成员那样访问它,即使用this关键字。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android