![](/img/trans.png)
[英]Typescript why am i able to to dynamically modify TypeScript object
[英]TypeScript: Why am I able to modify `readonly` property in constructor?
我有以下打字稿片段:
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 中的错误还是有意为之。 谁能解释一下?
文档只说
只读属性必须在其声明或构造函数中初始化。 (来源)
但正如 Romain 指出的,TypeScript 2.0 发行说明中有更多信息:
只读属性可能有初始值设定项,并且可以在同一个类声明中的构造函数中赋值,但不允许对只读属性赋值。 ( 来源)
但让我困惑的是编译后的输出。 请参阅TS Playground上的示例。
正如您所看到的,初始(只读)属性在编译时被覆盖,而没有来自 TS 的任何警告。 我猜这是故意的,因为语言的行为一直都一样,而且边缘情况更少。
编辑:还有一种“糖化”的方式来用 TypeScript 中的属性初始化一个class
(我想你知道但无论如何):
将public
/ private
添加到构造函数签名的参数会将这些参数初始化为类属性。 所以在你的例子中:
class Jedi {
constructor(
private readonly name: string = 'Skywalker'
) {}
toString():string {
return this.name;
}
}
如果让 TypeScript 编译上面的代码,它实际上会按预期工作(或者至少是我期望的那样)。 还有另一个指向操场的链接。
tl;博士; 如果没有给出,则通过public
/ private
在构造函数签名中初始化类属性将设置默认值。 如果您“手动”设置类属性( this.name = name
),这将不起作用。 后者可能仍然不是错误而是有意的行为,因为您显式设置了类属性。
你可以通过启用noImplicitAny
和strictNullChecks
来避免这个问题(或者至少让 TypeScript 向你尖叫)。 这样 TypeScript 会让你知道你的类属性可能是undefined
。
如果您想拥有不变性,我建议不要使用readonly
属性。 不仅上面提到的有点奇怪的行为,一些经验不足的开发人员还可能认为readonly
数组/对象在它不是的地方真的完全冻结/只读。 而是使用类似ImmutableJS 的东西。
声明为readonly
成员变量可以通过它们的声明进行赋值,也可以从构造函数中赋值。 对此有一定的 C# 熟悉。
示例 1
这里,只读成员变量是直接赋值的,如果你知道一个值是什么并且它永远不会改变,这很有用。
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;
})();
不变性呢?
readonly
仅由 TypeScript 及其编译器支持; JavaScript 中没有只读(嗯,这并不完全正确,只是 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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.