令人困惑的JavaScript继承行为
这让我感到困扰的原因是:令人困惑的JavaScript继承行为,javascript,oop,inheritance,prototype,constructor,Javascript,Oop,Inheritance,Prototype,Constructor,这让我感到困扰的原因是: JavaScript显然不像扫描属性那样扫描原型链中的方法。也就是说,f.SubFunction()生成一个错误 为了在原型上获得一个方法,每次你想做的时候,你必须至少经历3个点操作。最终类点原型点子函数点调用。你明白了 基类(原型)方法并没有像我期望的那样出现在Intellisense中。这很烦人 因此,我们的想法是确定如果我编写了一个版本的inherits,它将存根函数插入到子类中,然后为您委托回原型,会发生什么。例如,它将自动创建以下函数并将其添加到FinalCl
f.SubFunction()
生成一个错误李>
inherits
,它将存根函数插入到子类中,然后为您委托回原型,会发生什么。例如,它将自动创建以下函数并将其添加到FinalClass
:
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();
现在,我已经把所有的事情都安排好了。继承了方法,该方法是对象.prototype
和函数.prototype
的扩展,将函数
作为其唯一参数。这是基类。子类是通过分析Object.prototype.inherits.caller
确定的
从那里,我在子类上设置原型
和构造函数
,然后开始分析子类新原型上的方法。我构建了一个数组,其中包含原型和基类的公共接口上的方法。最终结果是一个很好的数组,其中包含通过原型或基类构造函数的return
语句公开的方法
一旦有了它,我就开始寻找子类上的每个方法。如果它不在那里,我将它添加到具有相同名称和签名的子类中。然而,方法体只是将调用转发给基类
现在,我可以一步一步地完成所有这些代码,它工作得非常出色,直到我实例化子类的实例为止。这就是事情变得不稳定的时候。下面是我使用Visual Studio 2008(SP1)和Internet Explorer 8观察到的情况:
在实例化之前,BaseClass
不公开任何公共方法。这是意料之中的。通过类构造函数的return
语句公开的方法在实例化之前不会出现。我对此很在行
在实例化之前,子类
公开了基类
中的方法。这正是我所期望的李>
一旦我声明了基类
的一个实例,它就拥有了我所期望的所有成员。它有自己的typeName
和BaseFunction
方法
一旦我声明了子类
的一个实例,它就只有构造函数的return
语句返回的那些方法了。基类中没有成员。在inherits方法中将基类方法映射到子类所做的所有工作似乎都丢失了
这里对我来说最大的谜团是我在继承执行过程中添加到子类中的方法消失了。在它的执行过程中,我可以清楚地看到子类正在被修改,基类的函数正在被传播。但当我创建一个子类时,这些信息就不再存在了
我假设这与构造函数、事件顺序或其他我根本看不到的东西有关
最后一点提示:这个项目的出现是为了了解JavaScript的复杂性及其原型继承系统的工作原理。我知道那里有现成的图书馆。我知道我正在重新发明轮子。我是故意重新发明它的。有时候,理解一件事的最好方法就是自己动手去做。这已经是一个巨大的学习经历,但我只是在这一点上被难住了
代码
function SubFunction() { SubClass.prototype.SubFunction.call(this); }
sti.objects.inherits=函数继承(基类){
var subClass=sti.objects.inherits.caller;
var baseClassName=sti.objects.getTypeName(baseClass);
var methods=sti.objects.getMethods(基类);
如果(!sti.objects.isDefined(baseClass.typeName))
baseClass.typeName=baseClassName;
var subClass=sti.objects.inherits.caller;
var subClassName=sti.objects.getTypeName(子类);
var temp=function(){};
temp.prototype=新基类();
子类原型=临时原型;
subClass.constructor=子类;
subClass.typeName=子类名称;
subClass.baseClass=baseClass.prototype;//原型方法的快捷方式
subClass.base=baseClass;//缓存构造函数
对于(var index=0;index
您的构造函数不是构造函数。当您使用new关键字时,Javascript会创建新对象,并期望您的构造函数使用成员等填充该对象。您的构造函数返回另一个新对象,与与构造函数使用相关的对象无关,因此原型无法工作
改变你的结构
function SubFunction() { SubClass.prototype.SubFunction.call(this); }
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();
function FinalClass() {
this.FinalFunction = function() { return "FinalFunction"; };
this.TypeName = "FinalClass";
this.SomethingSpectacular = function() {
return FinalClass.prototype.SubFunction.call(this);
};
}