<disclaimer>
What follows is the fruits of a thought experiment. What I'm doing
isn't the issue; the symptoms are. Thank you.
</disclaimer>
我终于在JavaScript中围绕构造函数,原型和原型继承。但下面示例中的SomethingSpectactular方法让我感到困惑:
function FinalClass() {
return {
FinalFunction : function() { return "FinalFunction"; },
TypeName : "FinalClass",
SomethingSpectacular : function() {
return FinalClass.prototype.SubFunction.call(this);
}
}
}
FinalClass.prototype = new SubClass();
FinalClass.constructor = FinalClass;
var f = new FinalClass();
这让我感到困惑的原因是:
f.SubFunction()
会产生错误。 因此,思想体验是确定如果我编写了一个inherits
版本,将存根函数插入到为您委托回原型的子类中会发生什么。例如,它会自动创建以下函数并将其添加到FinalClass
:
function SubFunction() { SubClass.prototype.SubFunction.call(this); }
现在,我已经完成了所有绘制和工作的内容。 inherits
方法是Object.prototype
和Function.prototype
的扩展,它以Function
为唯一参数。这是基类。通过分析Object.prototype.inherits.caller
来确定子类。
从那里,我在子类上设置prototype
和constructor
,然后开始分析子类的新原型上的方法。我在原型和基类的公共接口上构建了一个包含方法的数组。最终结果是一个很好的数组,它包含通过原型或基类构造函数的return
语句公开的方法。
有了这个,我开始在子类上寻找每个方法。如果它不存在,我将它添加到具有相同名称和签名的子类。但是,该方法的主体只是将调用转发给基类。
现在,我可以逐步完成所有这些代码并且它可以很好地工作,直到我实例化子类的实例。事情变得好运的时候。以下是我使用Visual Studio 2008(SP1)和Internet Explorer 8观察到的内容:
BaseClass
不公开任何公共方法。这是可以预料的。通过类构造函数的return
语句公开的方法在实例化之前不会出现。我很擅长。SubClass
公开了来自BaseClass
的方法。这正是我的预期。 BaseClass
的实例,它就拥有了我所期望的所有成员。它有typeName
和BaseFunction
方法。SubClass
的实例,它只有它的构造函数的return
语句返回的那些方法。没有来自基类的成员。在继承方法中将基类方法映射到子类的所有工作似乎都已丢失。对我来说,最大的谜团是我在执行继承时添加到SubClass的方法的消失。在执行期间,我可以清楚地看到正在修改SubClass,并且正在传播BaseClass的功能。但是,当我创建SubClass的实例时,该信息不再存在。
我假设这与构造函数,事件顺序或其他我根本看不到的东西有关。
最后的注释:这个项目的出现是为了理解JavaScript的复杂性及其原型继承系统的工作原理。我知道那里有现有的图书馆。我知道我正在重新发明轮子。我故意重新发明它。有时候,理解事物的最好方法就是自己构建它。这已经是一次巨大的学习经历,但我只是对这一点感到困惑。
代码
sti.objects.inherits = function inherits(baseClass) {
var subClass = sti.objects.inherits.caller;
var baseClassName = sti.objects.getTypeName(baseClass);
var methods = sti.objects.getMethods(baseClass);
if(!sti.objects.isDefined(baseClass.typeName))
baseClass.typeName = baseClassName;
var subClass = sti.objects.inherits.caller;
var subClassName = sti.objects.getTypeName(subClass);
var temp = function() {};
temp.prototype = new baseClass();
subClass.prototype = temp.prototype;
subClass.constructor = subClass;
subClass.typeName = subClassName;
subClass.baseClass = baseClass.prototype; // Shortcut to the prototype's methods
subClass.base = baseClass; // Cache the constructor
for(var index = 0; index < methods.items.length; index++) {
var resource = methods.items[index].getFunction();
var methodName = methods.items[index].getName();
if(methodName != "" && ! sti.objects.isDefined(subClass[methodName])) {
var method = sti.objects.createOverride(baseClassName, resource);
subClass[methodName] = method;
if(typeof subClass.prototype[methodName] == "undefined") {
subClass.prototype[methodName] = method;
}
}
}
}
Object.prototype.inherits = sti.objects.inherits;
Function.prototype.inherits = sti.objects.inherits;
function BaseClass() {
return {
A : function A() {return "A";}
};
}
function SubClass() {
inherits(BaseClass);
return {
B : function B() { return "B"; }
}
}
var b = new BaseClass();
var s = new SubClass();
答案 0 :(得分:4)
您的构造函数不是构造函数。当您使用new关键字时,Javascript会创建新对象,并期望您的构造函数使用成员等填充它。您的构造函数将返回另一个新对象,与与构造函数用法关联的对象无关,因此原型无法正常工作。
将构造函数更改为
function FinalClass() {
this.FinalFunction = function() { return "FinalFunction"; };
this.TypeName = "FinalClass";
this.SomethingSpectacular = function() {
return FinalClass.prototype.SubFunction.call(this);
};
}
你应该看到预期的继承行为。这是因为在这种情况下,FinalClass方法改变了通过“新”机制创建的上下文对象。您的原始方法是创建另一个不属于FinalClass类型的对象。