在 JavaScript(ES6) 的构造函数链中调用被子函数覆盖的父函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32615034/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Call parent function which is being overridden by child during constructor chain in JavaScript(ES6)
提问by andrew
I've encounter a problem below with JavaScript(ES6)
我在 JavaScript(ES6) 下面遇到了一个问题
class A{
constructor(){
this.foo();
}
foo(){
console.log("foo in A is called");
}
}
class B extends A{
constructor(){
super();
this.foo();
}
foo(){
console.log("foo in B is called");
}
}
What I expect is
我期望的是
foo in A is called
foo in B is called
But actually it is
但实际上是
foo in B is called
foo in B is called
I know I can resolve this by simply adding super.foo()
in class B's foo function
我知道我可以通过简单地添加super.foo()
B 类的 foo 函数来解决这个问题
class B extends A{
constructor(){
super();
this.foo();
}
foo(){
super.foo() // add this line
console.log("foo in B is called");
}
}
But imagine a scenario similar to this:
但是想象一个类似这样的场景:
Child has to override parent's function in order to do some extra works and prevent access from outer being able to access to the original one.
子级必须覆盖父级的功能才能做一些额外的工作并防止外部访问能够访问原始功能。
class B extends A{
constructor(){
super();
this.initBar();
}
foo(){
super.foo();
this.bar.run(); //undefined
console.log("foo in B is called");
}
initBar(){
this.bar.run = function(){
console.log("bar is running");
};
}
}
It seems that this
still points to child B
while constructing in parent A
. That's why I can't reach parent A
's foo
.
在 parent 中构建时似乎this
仍然指向 child 。这就是为什么我无法联系到 parent的.B
A
A
foo
How do I make this
to call parent version function which is being overridden by child during constructor chain?
如何this
调用在构造函数链中被子进程覆盖的父版本函数?
Or is there any better solution when it comes to scenario like this?
或者当涉及到这样的场景时有什么更好的解决方案吗?
Edit
编辑
So, after reading answers, the main question becomes --
所以,在阅读答案后,主要问题变成——
Is it discouraged to put initialize helpers
or setter functions
in constructor in JavaScript since children have a chance to override them?
是否不鼓励在 JavaScript 中放入initialize helpers
或setter functions
放入构造函数,因为孩子有机会覆盖它们?
To clarify the situation more clearly: (sorry for my previous bad example :( )
为了更清楚地澄清情况:(对不起,我以前的坏例子:()
class A{
constructor(name){
this.setName(name);
}
setName(name){
this._name = name;
}
}
class B extends A{
constructor(name){
super(name);
this._div = document.createElementById("div");
}
setName(name){
super.setName(name);
this._div.appendChild(document.createTextNode(name));
}
}
new B("foo")
this._div
will be undefined
.
this._div
将undefined
。
Is this a bad idea since child will be able to override the function?
这是一个坏主意,因为孩子将能够覆盖该功能?
class A{
constructor(name){
this.setName(name); // Is it bad?
}
...
}
So I shouldn't use initialize helpers
or setter functions
in constructor like in Java, C++...?
所以我不应该像 Java、C++ 那样在构造函数中使用initialize helpers
或setter functions
......?
Must I manually call things like this new A().init()
to help me initialize things?
我必须手动调用这样的东西new A().init()
来帮助我初始化吗?
回答by jfriend00
You seem to be operating under a misconception that there are two objects A
and B
when you are in the constructor of the derived class B
. This is not the case at all. There is one and only one object. Both A
and B
contribute properties and methods to that one object. The value of this
will be the same in the constructor for B
as it is in the constructor for A
during the creation of an object of class B.
您似乎误以为有两个对象A
并且B
您在派生类的构造函数中B
。事实并非如此。有一个并且只有一个对象。无论A
和B
贡献的属性和方法的一个对象。的值this
在构造函数B
中将与A
在创建类 B 的对象期间在构造函数中相同。
The ES6 class syntax is just sugar over the ES5 method of using prototypes for object types and, in fact, the prototype is still used under the covers. As such, when you define a method foo
in a derived class like you do in class B, it is still assigning to the prototype and that assignment overrides any method of the same name that might already exist on the prototype that came from the parent definition. This is why this.foo()
refers to the class B version of foo
. If you want to reach the class A version of foo
, then you will have manually specify that using super
as you appear to already know.
ES6 类语法只是对 ES5 使用对象类型原型的方法的糖,事实上,原型仍然在幕后使用。因此,当您foo
像在类 B 中那样在派生类中定义一个方法时,它仍然会分配给原型,并且该分配会覆盖来自父定义的原型上可能已经存在的任何同名方法。这就是为什么this.foo()
指的是 B 类版本的foo
. 如果您想达到 的 A 类版本foo
,那么您必须手动指定使用super
您似乎已经知道的方法。
As for your specific questions:
至于你的具体问题:
It seems that this still points to child B while constructing in parent A. That's why I can't reach parent A's foo.
似乎这在父 A 中构造时仍然指向子 B。这就是为什么我无法到达父 A 的 foo。
child B and parent A are not separate objects. There is one object that both parent A and child B reference. parent A and child B methods or constructors will see the exact same value of this
.
子 B 和父 A 不是单独的对象。父 A 和子 B 都引用了一个对象。父 A 和子 B 方法或构造函数将看到完全相同的this
.
How do I make this to call parent version function which is being overridden by child during constructor chain?
我如何使它调用在构造函数链期间被子进程覆盖的父版本函数?
You use super
to reference parent methods directly as you appear to already know.
super
正如您似乎已经知道的那样,您使用直接引用父方法。
Or is there any better solution when it comes to scenario like this?
或者当涉及到这样的场景时有什么更好的解决方案吗?
super
is the solution.
super
是解决方案。
FYI, this is a pretty good discussion on ES6 classes including how super
works: Classes in ECMAScript 6 (final semantics). Section 4.4 seems particularly relevant to your question/understanding.
仅供参考,这是关于 ES6 类的一个很好的讨论,包括如何super
工作:ECMAScript 6 中的类(最终语义)。第 4.4 节似乎与您的问题/理解特别相关。