为什么我无法访问TypeScript私有成员?

Sea*_*man 102 javascript typescript

我正在寻找TypeScript中私有成员的实现,我发现它有点令人困惑.Intellisense不允许访问私有成员,但在纯JavaScript中,它就在那里.这让我觉得TS没有正确实现私有成员.有什么想法吗?

class Test{
  private member: any = "private member";
}
alert(new Test().member);
Run Code Online (Sandbox Code Playgroud)

Guf*_*ffa 90

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

私有属性是作为常规属性实现的,并且不允许类外的代码访问它.

要在类中创建真正私有的东西,它不能是类的成员,它将是在创建对象的代码内的函数范围内创建的局部变量.这意味着你不能像类的成员那样访问它,即使用this关键字.

  • 这是我一直在提供的反馈.我相信它应该提供创建Revealing Module Pattern的选项,因此私有成员可以保持私有,并且可以使用JavaScript访问公共成员.这是一种常见模式,可在TS和JS中提供相同的可访问性. (37认同)
  • javascript程序员将局部变量放在对象构造函数中并将其用作私有字段并不罕见.我很惊讶他们不支持这样的事情. (22认同)
  • @Eric:由于TypeScript使用原型进行方法而不是在构造函数中添加方法作为原型,因此无法从方法中访问构造函数中的局部变量.有可能在类的函数包装器中创建一个局部变量,但我还没有找到一种方法.但是,这仍然是局部变量,而不是私有成员. (2认同)

Mar*_*tin 36

JavaScript确实支持私有变量.

function MyClass() {
    var myPrivateVar = 3;

    this.doSomething = function() {
        return myPrivateVar++;        
    }
}
Run Code Online (Sandbox Code Playgroud)

在TypeScript中,这将表达如下:

class MyClass {

    doSomething: () => number;

    constructor() {
        var myPrivateVar = 3;

        this.doSomething = function () {
            return myPrivateVar++;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑

这种方法只能用于少量的地方是绝对必要的.例如,如果您需要临时缓存密码.

使用这种模式会产生性能成本(与Javascript或Typescript无关),只能在绝对必要的地方使用.

  • 更准确地称它们为构造函数变量,而不是私有变量。这些在原型方法中是不可见的。 (2认同)

Prz*_*ski 19

由于 TypeScript 3.8 将发布,您将能够声明在包含 class 之外无法访问甚至无法检测到的私有字段 。

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.
Run Code Online (Sandbox Code Playgroud)

私有字段以#字符开头

请注意,这些私有字段将与用private关键字标记的字段不同

参考 https://devblogs.microsoft.com/typescript/annoucing-typescript-3-8-beta/


Rya*_*mas 11

一旦支持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)();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • @RamtinSoltani 链接的文章统计表明,由于弱图的工作方式,这不会阻止垃圾收集。如果有人想在使用这种技术时更加安全,他们可以实现自己的处理代码,从每个弱映射中删除类实例键。 (2认同)

ale*_*ird 5

感谢 Sean Feldman 提供有关此问题的官方讨论的链接 - 请参阅对链接的回答

我阅读了他链接到的讨论,以下是要点摘要:

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

在发出的代码中添加可见性支持的总体反驳:

  • 问题是 JavaScript 本身没有可见性修饰符——这不是 TypeScript 的问题
  • JavaScript 社区中已经有一个既定的模式:在私有属性和方法前面加上下划线,表示“风险自担”
  • 当 TypeScript 设计者说真正的私有属性和方法不是“可能的”时,他们的意思是“在我们的设计约束下不可能”,特别是:
    • 发出的 JS 是惯用的
    • 样板是最小的
    • 与普通的 JS OOP 相比没有额外的开销

  • 是的,这就是对话 - 但我链接到 [Sean Feldman 对这个问题的回答](http://stackoverflow.com/a/12713927/3012550),他在那里提供了链接。由于他做了寻找链接的工作,我想给他功劳。 (2认同)