我不是Javascript专家,但我遇到了一个我无法解释的非常奇怪的情况。 我想看看你们中的一些人是否可以帮我理解: - )
首先,让我们看看工作正常的部分:
我想设置三个类,一个是其他类的基类,如下所示:
Base
|- Atom
|- Button
这是我使用的代码:
//-------------------------------------------------------------------
function Base() {
this.values = {
a: true,
b: false
};
}
Base.prototype.display = function() {
for(i in this.values) {
window.console.log(i + ' : ' + this.values[i]);
}
window.console.log('---');
}
//-------------------------------------------------------------------
function Atom() {
this.values.a = false;
this.values.c = 'test';
}
Atom.prototype = new Base();
//-------------------------------------------------------------------
function Button() {
this.display(); // displays part (1)
this.atom = new Atom();
this.display(); // displays part (2)
this.atom.display(); // displays part (3)
}
Button.prototype = new Base();
//-------------------------------------------------------------------
new Button();
" Base" class有一个名为"的值"这是一组价值观。 "显示"方法只显示"值"属于控制台。
" Atom" class继承了"值"来自" Base"的财产,它只是改变 " a"的价值并添加一个新的" c"。
"按钮" class有一个属性,它是Atom类的一个对象。 它称之为"显示"创建其原子"之前和之后的方法 属性,然后它也调用"显示" " atom"的方法本身。
到目前为止,这么好。这是屏幕上的结果:
a : true // part (1)
b : false
---
a : true // part (2)
b : false
---
a : false // part (3)
b : false
c : test
---
前两组值(1)和(2)来自Button类,第三组(3)来自Atom 类,已修改" a"并添加了" c"。
当我想在" Base"之间添加一个中间类时出现问题。和它的 后代,像这样:
Base
|- Widget
|- Atom
|- Button
这里是使用新" Widget"的代码。类:
//-------------------------------------------------------------------
function Base() {
this.values = {
a: true,
b: false
};
}
Base.prototype.display = function() {
for(i in this.values) {
window.console.log(i + ' : ' + this.values[i]);
}
window.console.log('---');
}
//-------------------------------------------------------------------
function Widget() {
}
Widget.prototype = new Base();
//-------------------------------------------------------------------
function Atom() {
this.values.a = false;
this.values.c = 'test';
}
Atom.prototype = new Widget();
//-------------------------------------------------------------------
function Button() {
this.display(); // displays part (1)
this.atom = new Atom();
this.display(); // displays part (2)
this.atom.display(); // displays part (3)
}
Button.prototype = new Widget();
//-------------------------------------------------------------------
new Button();
正如您所看到的," Atom"的基本原型。和"按钮"班级有 已更改为" Widget"而不是" Base"。
事情变得奇怪的事情:
a : true // part (1)
b : false
---
a : false // part (2)
b : false
c : test
---
a : false // part (3)
b : false
c : test
---
第一组(创建" atom"之前)保持不变。 但是按钮的值将在创建" atom"之后立即更改, 它们现在与" atom"的相同,这不是我的预期。
这就是我不明白的原因。 创建原子时,它会修改自己的一组值,但为什么 是否也修改了按钮的值?
我想" Button.values"和" Button.atom.values"会是两件事, 但看起来他们分享了他们的价值观,但只有中间人才能这样做 "窗口小部件" class是两者的父母" Button"和#34; Atom"。
这对我很困惑...... 我希望我的解释清楚,不要犹豫告诉我,如果不是这样。
非常感谢你的时间和答案:-) 马克。
答案 0 :(得分:3)
values
指的是一个对象,并且由于您实现伪经典继承的方式,只有一个对象分配给该属性,其结束在原型之间共享。您的Widget
和Atom
最终都使用相同的对象。
使用JavaScript设置伪古典继承时,您会看到您经常使用的模式,但这很不幸,因为它存在重大问题(包括此问题)。具体来说,调用Base
来创建原型Atom
(等等)是一个问题,因为通常,像Base
这样的构造函数被设计为在构造实例时使用。我通常用它们标记的问题是:如果Base
需要接受特定于实例的参数,该怎么办?在创建Atom
原型时,您会给出什么参数?
相反,在构造实例之前,不要调用构造函数。要构建原型,请创建一个新对象,该对象使用父"类"的原型作为其基础原型,如下所示:
function Parent() {
}
function Child() {
Parent.call(this);
// Child initialization goes here
}
Child.prototype = Object.create(Parent.prototype); // Not `new Parent()`
Child.prototype.constructor = Child;
(如有必要,您可以为ES5之前的引擎填充Object.create
的单参数版本。)
可能解决您问题的原因是使用此模式,在创建每个实例时会调用Base
函数,这意味着它会创建一个新对象并将其分配给values
属性在那个例子上。
附注:为了节省详细程度并获得一些功能,我创建了一个名为Lineage
的小帮助脚本来设置伪古典层次结构。它简化了语法,调用了超级"类"方法的版本简单,以及其他各种各样的东西。