我有以下代码结构,我尝试通过调用super()来初始化父类,但是当我调用this._init()时,它会调用其中一个子代码。任何帮助我该如何解决这个问题?
class Parent {
constructor() {
console.log('P constructor()');
this._init();
}
_init() {
console.log('P _init()');
this.parentProp = 'parent';
}
}
class Child extends Parent {
constructor() {
console.log('C constructor');
super();
this._init();
}
_init() {
console.log('C _init()');
this.childProp = 'child';
}
test() {
console.log(this.childProp + ' ' + this.parentProp);
}
}
let child = new Child();
child.test();
以下是上述代码的输出:
C constructor()
P constructor()
C _init()
C _init()
child undefined
答案 0 :(得分:3)
Child#_init
被调用,因为当调用_init
(在this._init()
中)时,对象的Parent
属性就是这样。会发生什么(遗漏一些细节)是:
new
创建一个[[Prototype]]
为Child.prototype
的新对象。 Child.prototype
的{{1}}是[[Prototype]]
。Parent.prototype
来电new
。Child
来电Child
。Parent
在对象上查找this._init()
属性。由于该对象没有自己的_init
属性,因此JavaScript引擎会查找其_init
。 [[Prototype]]
具有Child.prototype
属性,因此引擎会使用该属性。至于解决它:JavaScript类只有一个构造函数,所以没有真正的目的来拥有一个单独的_init
函数。 1 这就是构造函数的用途。尽管他们的名字,他们不构造对象,他们初始化他们。所以只需将_init
的代码放在构造函数本身中:
_init
或者,只需完全从class Parent {
constructor() {
console.log('P constructor');
this.parentProp = 'parent';
}
}
class Child extends Parent {
constructor() {
console.log('C constructor');
super();
this.childProp = 'child';
}
test() {
console.log(this.childProp + ' ' + this.parentProp);
}
}
let child = new Child();
child.test();
移除this._init()
来电,然后Child
拨打Child#_init
。我知道你在评论中说过你认为这是不好的做法(不是,这是标准做法),但是如果你想突破super._init()
来分离职能,那就是你所做的。但这样做违反了主要的,完善的跨语言,从构造函数(_init
调用Parent
)调用可重写方法是一个坏主意™。 : - )
如果你绝对坚持将代码分离到一个函数中,并且不想在this._init()
中使用super._init()
,那么它将需要与该类分开:
Child#_init
1 我可以看到在一个带有重载构造函数的语言中使用一个方法 - 尽管在那里我主张让它们相互调用而不是实用方法 - 但不是在JavaScript中。
答案 1 :(得分:1)
最好的解决方案是根本不使用true
方法。构造函数不应该调用可覆盖的方法:
init
或者,在您的情况下,它可以在class Parent {
constructor() {
console.log('P constructor()');
this.parentProp = 'parent';
}
}
class Child extends Parent {
constructor() {
console.log('C constructor');
super();
this.childProp = 'child';
}
test() {
console.log(this.childProp + ' ' + this.parentProp);
}
}
let child = new Child();
child.test();
中调用super方法,而不是从Child构造函数调用_init
:
_init
答案 2 :(得分:0)
基本上我们的情况import {Link} from "react-router";
interface LinkProps {
to?: HistoryModule.LocationDescriptorObject;
onClick?: (event: React.FormEvent) => void;
children?: React.ReactNode;
}
const LinkPresenter: React.SFC = (props: LinkProps): JSX.Element =>
<Link
className="link"
to={props.to}
onClick={props.onClick}
>
{props.children}
</Link>;
// Alternative syntax
const LinkPresenter: React.StatelessComponent = (props: LinkProps): JSX.Element =>
...
LinkPresenter.defaultProps = { // now we can use defaultProps
to: {
pathname: `/homepage`,
query: {
default: 'someDefault'
}
},
onClick: () => {},
children: <span>Hello world</span>,
};
等于super()
,其中Parent.call(this)
指向this
。因此,Child
将被调用两次,并且不会创建属性Child.prototype._init
。
这就是为什么你会看到以下控制台输出。
parentProp