我有以下打字稿class
:
class Jedi {
private readonly name: string = 'Skywalker';
constructor(name: string) {
this.name = name; //Why I am able to modify name.
}
toString():string {
return this.name;
}
}
var jedi = new Jedi('Kenobi');
console.log(jedi.toString()); //Kenobi
正如您在代码中看到的,我已将name
属性声明为readonly
。根据我的知识将属性声明为常量,我们在typescript 中使用readonly
。一旦我们用初始化声明它,我们就无法修改它。但正如您在constructor
中所看到的那样,它正在被修改。此外typescript
编译器也不会对此发出警告。不确定它是typescript
中的错误还是故意的。有人可以解释一下吗?
答案 0 :(得分:3)
文档只说
必须在声明或构造函数中初始化Readonly属性。 (Source)
但正如Romain所指出的那样,TypeScript 2.0发行说明中还有更多信息:
只读属性可能具有初始值设定项,并且可能在同一类声明中的构造函数中分配,但是不允许对只读属性进行赋值。 (Source)
但是令我困惑的是编译输出。请参阅TS Playground上的示例。
正如您所看到的那样,初始(readonly)属性在编译时没有来自TS的任何警告时被覆盖。我想这是故意的,因为语言的行为始终相同,边缘情况也较少。
编辑:还有一个"糖化"使用TypeScript中的属性初始化class
的方法(我想你知道但是无论如何):
将public
/ private
添加到构造函数签名的参数中会将这些参数初始化为类属性。所以在你的例子中:
class Jedi {
constructor(
private readonly name: string = 'Skywalker'
) {}
toString():string {
return this.name;
}
}
如果让TypeScript编译上面的代码,它实际上按预期工作(或者至少是我期望的)。还有另一个Link to the Playground。
tl; dr; 如果没有给出,则通过public
/ private
在构造函数签名内初始化类属性将设置默认值。如果您设置类属性"手动"这不起作用。 (this.name = name
)。后者可能仍然不是错误,而是故意行为,因为您明确设置了类属性。
您可以启用noImplicitAny
和strictNullChecks
来避免此问题(或至少让TypeScript尖叫)。这样,TypeScript会通知您,您的类属性可能是undefined
。
如果您想拥有不变性,我建议不使用readonly
属性。上面提到的不仅仅是一种奇怪的行为,一些经验不足的开发人员也可能认为readonly
数组/对象只是在它不是真正完全冻结/读取的地方。而是使用ImmutableJS之类的东西。
答案 1 :(得分:0)
答案 2 :(得分:0)
声明为readonly
的成员变量可以使用其声明或构造函数进行分配。 C#对此有一定的了解。
示例1
这里,readonly成员变量是直接分配的,如果您知道某个值是什么,并且它永远不会改变,这将非常有用。
class Foo {
public readonly bar: number = 123;
}
示例2
这里,声明了readonly成员变量,然后从构造函数中赋值,如果你还不知道最终值,这很有用,但是一些构造函数逻辑会为你解决这个问题。
class Foo {
public readonly bar: number;
constructor(bar: number) {
this.bar = 123 * bar / 100;
}
}
示例3
这里readonly成员变量使用TypeScript的简写成员变量声明,其中可以从构造函数中分配全局成员变量,如果您希望用户输入一个永不改变的值,这将非常有用。在此特定示例中,bar
可以由用户设置,也可以默认为123
。
class Foo {
constructor(public readonly: bar: number = 123) {
}
}
示例4
这是您不想做的事情,因为发出的JavaScript会导致对同一个变量进行两次分配。 我只是添加了这个,以便未来的开发者知道他们可能不应该这样做。
class Foo {
public readonly bar: number = 123;
constructor(bar: number) {
this.bar = bar;
}
}
发出的JavaScript看起来像这样......
var Foo = (function () {
function Foo(bar) {
this.bar = 123; // :)
this.bar = bar; // :(
}
return Foo;
})();
不变性怎么办?
只有TypeScript及其编译器支持 readonly
; JavaScript 中没有readonly(嗯,这并不完全正确,只是TypeScript没有发出真正的只读值)。这个有几种解决方法(是的,如果TypeScript可以为我们发出这些,那就太好了!)
创建不可变成员变量
class Foo {
// TypeScript respects "readonly"
public readonly bar: number;
constructor(bar: number) {
// JavaScript respects property that isn't writable.
Object.defineProperty(this, "bar", {
value: bar,
enumerable: true,
configurable: false,
writable: false
});
}
}
创建不可变类
class Foo {
constructor(public readonly bar: number) {
// Nothing in the object is allowed to be reassigned.
Object.freeze(this);
}
}