ES6调用super()没有正确初始化父类 [英] ES6 calling super() doesn't properly initialize parent class
问题描述
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构造函数()
P构造函数()
C _init()
C _init()
child undefined
Child#_init
正在调用,因为这是$ _init
属性对象是指当$ code> this._init()(在code> Parent )被调用。发生什么(省略一些细节)是:
-
新
创建一个新对象其[[Prototype]]
是Child.prototype
。Child.prototype
的[[Prototype]]
是Parent.prototype
。 -
new
callChild
。 -
Child
callParent
。 -
this._init()
查找对象上的_init
属性。由于该对象没有自己的_init
属性,因此JavaScript引擎将查找其[[Prototype]]
。Child.prototype
具有_init
属性,因此引擎使用该属性。 / li>
至于解决它:JavaScript类只有一个构造函数,所以没有真正的目的,要有一个单独的 _init
function。 1 这是什么构造函数。尽管他们的名字,他们不构造对象,他们初始化他们。所以只需在构造函数本身中放入 _init
的代码:
class Parent {constructor(){console.log('P constructor'); this.parentProp ='parent'; }} class Child extends Parent {constructor(){console.log('C constructor');超(); this.childProp ='child'; } test(){console.log(this.childProp +''+ this.parentProp); }} let child = new Child(); child.test();
另外,只需从 Child
中删除 this._init()
调用,并且 Child#_init
call super._init()
。我知道你在一个评论中说过,你认为这是不好的做法(这不是标准做法),但是如果你想打破 _init
来分离功能,这就是你所做的但是这样做违反了主要的,完善的跨语言,从构造函数( Parent
调用 this._init()
)是Bad Idea™。 : - )
如果您绝对坚持将代码分离成一个函数,并且不想使用 super._init()
在 Child#_init
中,需要与课程分开:
div class =snippetdata-lang =jsdata-hide =falsedata-console =truedata-babel =false>
1 我可以看到使用一种具有重载构造函数的语言的方法 —虽然即使在那里,我主张让他们打电话给对方,而不是一个实用方法 —但不在JavaScript中。
I have the following code structure, I try to initialize parent class by calling super(), but when i call this._init() it calls the one of the child. any help how can I fix this?
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();
Here's the output of the above code:
C constructor()
P constructor()
C _init()
C _init()
child undefined
Child#_init
is getting called because that's what the _init
property on the object refers to when this._init()
(in Parent
) is called. What happens (leaving out some details) is:
new
creates a new object whose[[Prototype]]
isChild.prototype
.Child.prototype
's[[Prototype]]
isParent.prototype
.new
callsChild
.Child
callsParent
.this._init()
looks up the_init
property on the object. Since the object doesn't have its own_init
property, the JavaScript engine looks to its[[Prototype]]
.Child.prototype
does have an_init
property, so the engine uses that one.
As for solving it: JavaScript classes have only one constructor, so there's no real purpose to having a separate _init
function.1 That's what constructors are for. Despite their name, they don't construct objects, they initialize them. So just put _init
's code in the constructor itself:
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();
Alternately, just remove the this._init()
call from Child
entirely and have Child#_init
call super._init()
. I know you've said in a comment you think that's poor practice (it isn't, it's standard practice), but if you want to break out _init
to separate functions, that's what you do. But doing so violates the principal, well-established cross-language, that calling overrideable methods from a constructor (Parent
calling this._init()
) is a Bad Idea™. :-)
If you absolutely insist on separating the code out into a function, and don't want to use super._init()
in Child#_init
, it'll need to be separate from the class:
let Parent = (function() {
class Parent {
constructor() {
console.log('P constructor');
initParent.call(this);
}
}
function initParent() {
console.log("initParent");
this.parentProp = 'parent';
}
return Parent;
})();
let Child = (function() {
class Child extends Parent {
constructor() {
console.log('C constructor');
super();
initChild.call(this);
}
test() {
console.log(this.childProp + ' ' + this.parentProp);
}
}
function initChild() {
console.log("initChild");
this.childProp = 'child';
}
return Child;
})();
let child = new Child();
child.test();
1 I could see using a method in a language with overloaded constructors — although even there I advocate having them call each other rather than a utility method — but not in JavaScript.
这篇关于ES6调用super()没有正确初始化父类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!