TypeScript类的只读属性

10
我注意到TypeScript 2.0将支持只读类属性,但目前还不可用。我写这篇文章的原因是希望能够聪明地编写代码,以便稍后在转换时尽可能少地遇到问题。
我想这样使用一个带有只读属性的类:
let widget = new Widget(110, 220); // width, height
//...
widget.width(200); // to modify the width, I use a setter with validation
widget.width = 300; // note: I want this to be a compile time error
//...
let w = widget.width; // and later I want to get/draw the current width

...但由于fn和property名称相同,我无法使其工作-因此,我将切换fn名称为setWidth。 我不想给所有只读属性加前缀_,因为过去我发现这样做比键入额外字符的麻烦更大。 由于TS的类型检查,我不需要视觉提醒属性是只读的(或私有的)。

Q1:如果宽度是widget类的只读属性,上述代码在typescript 2中是否有效?

export class widget {
    readonly width:number;  // doesn't work in TS 1.8

    setWidth(w:number) {
        this.width = w;
    }
}

在短期内,我可以将属性公开,以便我可以直接访问,但这样会“风险”我可能会直接设置属性 - 或者我可以有私有属性并编写getter和setter。
问题二:如果我选择后者,getter的速度比直接引用属性慢多少?我的一些属性在拖动时会被频繁调用,因此速度很重要。
widget.getWidth();
// vs
widget.width;

更新

我最近发现了这个帖子的回答,并意识到TS已经支持了我尝试做的大部分内容:

export class Widget {
    private _width:number;
    set width(w) {if (w >= 0) this._width = w}
    get width() {return this._width}
}

使用语法与没有访问器的公共属性相同,这真的非常方便:

let widget = new Widget(...);
let existingWidth = widget.width;
widget.width = newWidth;

我希望TS2的readonly限定符能够直接读取(私有)属性(不通过访问器函数,因此更快),并且我的所有使用代码都不需要更改。有人知道吗?


属性访问器可能会慢20倍,而且性能非常依赖于浏览器。请参见以下jsPerf - https://jsperf.com/data-vs-accessor-vs-getter-setter/2 - bnieland
我运行了最新版本的jsperf,操作/秒数似乎不真实地高。它告诉我,在我的机器上,Firefox在少于1纳秒的时间内运行getter函数。这似乎不可能...除非它自动将工作分散到我Mac的4个核心上-在这种情况下,它大约是4-5纳秒,但仍然不真实。 - bedouger
编写自己的测试非常容易。使用属性getter与访问数据值100,000次相比,需要多长时间? - bnieland
1
@bnieland,这种测试也很容易出错,要注意。 - Bartek Banachewicz
@bedouger,你能解释一下吗?“我希望TS2的readonly修饰符能直接访问(私有)属性(而不是通过访问器函数,所以更快),并且我的使用代码都不需要改变。” - robyoder
我的思路: 在ts 1.x中,最接近readonly的是export class(以上“UPDATE”下面),在那里我可以选择不在setter中执行任何操作。 如果我没有定义getter,则无法在该类外读取该值,因此我定义了一个getter。 当我说let existingWidth = widget.width时,它会运行getter函数(比直接访问该值慢一点)。 在ts 2.0中,我认为可以将width声明为readonly而不定义getter或setter。 然后,当我说let existingWidth = widget.width时,它将直接访问该值而不运行函数。 - bedouger
1个回答

10

现在我正在使用TS2,我发现readonly不是我想要的,因为只读限制甚至适用于类内部。所以我能想到的最好方法是使用private修饰符并编写一个显式的getter方法。这有两个不幸的原因:读取速度较慢(可能),而getter方法名必须与私有变量的名称不同。


似乎没有办法在构造函数之外初始化只读值。C# 有 myThing = new Thing(){param=val,param2=val2},但我认为 TypeScript 还没有这个功能。 - Eric Hartford
除非您有特定的担忧,否则不必担心访问速度。至于命名,只需在getter中使用“property_name”,在私有变量中使用“_property_name”。在大多数语言中,使用前导下划线表示私有成员是一种广为认可的惯例。 - Neutrino
1
那么//@ts-ignore只在setter中使用呢?我知道这可能被视为不良实践,但在这种情况下,我认为它是有补偿作用的。 - tru7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接