【发布时间】:2015-09-16 17:28:14
【问题描述】:
我在下面的 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");
}
}
我期待的是
foo in A is called
foo in B is called
其实是这样的
foo in B is called
foo in B is called
我知道我可以通过在 B 类的 foo 函数中简单地添加 super.foo() 来解决这个问题
class B extends A{
constructor(){
super();
this.foo();
}
foo(){
super.foo() // add this line
console.log("foo in B is called");
}
}
但是想象一个类似这样的场景:
孩子必须重写父母的功能才能做一些额外的工作并防止外部访问能够访问原始的。
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");
};
}
}
似乎this 在父A 中构造时仍指向子B。这就是为什么我无法联系到父母A 的foo。
如何让this 在构造函数链中调用被子版本覆盖的父版本函数?
或者对于这样的场景有没有更好的解决方案?
编辑
所以,看完答案后,主要问题就变成了——
不鼓励将initialize helpers 或setter functions 放在JavaScript 的构造函数中,因为孩子有机会覆盖它们?
为了更清楚地说明情况:(对不起我之前的坏例子:()
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 将是 undefined。
这是一个坏主意,因为孩子将能够覆盖该功能?
class A{
constructor(name){
this.setName(name); // Is it bad?
}
...
}
所以我不应该在构造函数中使用initialize helpers 或setter functions,比如Java、C++...?
我必须手动调用 new A().init() 这样的东西来帮助我初始化吗?
【问题讨论】:
-
如何让
this调用父版本函数 -super是唯一的方法。 -
为什么
A构造函数调用this.foo()?它不应该,它应该只初始化实例。 -
子
foo是打算在一般原因中覆盖父实现,还是您更想问如何使“foo”成为一些私人助手? -
ES6 类语法仍在生成原型,就像我们过去手工编写代码一样。所以,当你在 B 类中定义
foo时,它仍然会覆盖原型上foo的定义,而这个this.foo()无论你在哪里调用它都会引用 B 类的定义。您似乎已经知道,如果您想调用 foo 的 A 类版本,您必须手动进行。 -
仅供参考,您似乎认为有两个对象,一个给孩子,一个给父母。这不是它的工作方式。
this不指向子 B。this指向整个对象,其中 A 和 B 都有实例上的属性和原型上的方法。只有一个对象同时具有 A 和 B 贡献的属性和方法。这就是为什么也只有一个this以及为什么this.foo指向最近的覆盖。
标签: javascript class constructor this ecmascript-6