打字稿:无法访问继承类构造函数中的成员值 [英] Typescript: can not access member value in inherited class constructor
问题描述
我有一个 A
类和一个从它继承的 B
类.
I have a class A
, and a class B
inherited from it.
class A {
constructor(){
this.init();
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
当我运行此代码时,出现以下错误:
When I run this code, I get the following error:
Uncaught TypeError: Cannot read property 'value' of undefined
我怎样才能避免这个错误?
How can I avoid this error?
我很清楚 JavaScript 代码将在创建 myMember
之前调用 init
方法,但应该有一些实践/模式才能使其工作.
It's clear for me that the JavaScript code will call the init
method before it creates the myMember
, but there should be some practice/pattern to make it work.
推荐答案
这就是为什么在某些语言(咳咳 C#)中,代码分析工具会标记构造函数中虚拟成员的使用情况.
This is why in some languages (cough C#) code analysis tools flag usage of virtual members inside constructors.
在 Typescript 中,字段初始化发生在构造函数中,在调用基本构造函数之后.字段初始化写在字段附近的事实只是语法糖.如果我们查看生成的代码,问题就很清楚了:
In Typescript field initializations happen in the constructor, after the call to the base constructor. The fact that field initializations are written near the field is just syntactic sugar. If we look at the generated code the problem becomes clear:
function B() {
var _this = _super.call(this) || this; // base call here, field has not been set, init will be called
_this.myMember = { value: 1 }; // field init here
return _this;
}
您应该考虑一个解决方案,其中 init 从实例外部调用,而不是在构造函数中调用:
You should consider a solution where init is either called from outside the instance, and not in the constructor:
class A {
constructor(){
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
x.init();
或者,您可以为构造函数添加一个额外的参数,指定是否调用 init
而不是在派生类中也调用它.
Or you can have an extra parameter to your constructor that specifies whether to call init
and not call it in the derived class as well.
class A {
constructor()
constructor(doInit: boolean)
constructor(doInit?: boolean){
if(doInit || true)this.init();
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor()
constructor(doInit: boolean)
constructor(doInit?: boolean){
super(false);
if(doInit || true)this.init();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
或者 setTimeout
的非常非常非常肮脏的解决方案,它将延迟初始化,直到当前帧完成.这将让父构造函数调用完成,但在构造函数调用和超时到期之间会有一个过渡,当对象没有被init
ed
Or the very very very dirty solution of setTimeout
, which will defer initialization until the current frame completes. This will let the parent constructor call to complete, but there will be an interim between constructor call and when the timeout expires when the object has not been init
ed
class A {
constructor(){
setTimeout(()=> this.init(), 1);
}
init(){}
}
class B extends A {
private myMember = {value:1};
constructor(){
super();
}
init(){
console.log(this.myMember.value);
}
}
const x = new B();
// x is not yet inited ! but will be soon
这篇关于打字稿:无法访问继承类构造函数中的成员值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!