whe*_*hys 6 javascript inheritance prototypal-inheritance backbone.js
我正在使用一个改编自Backbone的扩展功能(除了一些改变,以符合我雇主的命名惯例),以实现原型继承.在设置了以下结构(下面简化得很简单)之后,我得到了一个无限循环.
Graph = function () {};
Graph.extend = myExtendFunction;
Graph.prototype = {
generateScale: function () {
//do stuff
}
}
// base class defined elsewhere
UsageGraph = Graph.extend({
generateScale: function () {
this.constructor._super.generateScale.call(this); // run the parent's method
//do additional stuff
}
})
ExcessiveUsageGraph = Graph.extend({
// some methods, not including generateScale, which is inherited directly from Usage Graph
})
var EUG = new ExcessiveUsageGraph();
EUG.generateScale(); // infinite loop
Run Code Online (Sandbox Code Playgroud)
循环正在发生,因为ExcessiveUsageGraph上升原型链来UsageGraph运行方法,但this仍然设置为一个实例,ExcessiveUsageGraph当我this.constructor._super用来运行父方法时,它也向上一步到达UsageGraph并再次调用相同的方法.
如何从Backbone样式的原型中引用父方法并避免这种循环.如果可能的话,我还想避免按名称引用父类.
Der*_*ley 12
您正在this尝试使用JavaScript 和原型继承的一个限制,因为您试图在不直接支持它的语言中创建类类继承方案.
即使使用Backbone,由于您已经概述的限制等等,您通常不会直接使用"超级".
常见的解决方案是直接调用原型对象,而不是试图通过使用"超级"引用来掩盖它.
UsageGraph = Graph.extend({
generateScale: function () {
Graph.prototype.generateScale.call(this); // run the parent's method
//do additional stuff
}
})
Run Code Online (Sandbox Code Playgroud)
在一个工作的JSFiddle:http://jsfiddle.net/derickbailey/vjvHP/4/
这个工作的原因与JavaScript中的"this"有关.调用函数时,"this"关键字是根据调用函数的方式设置的,而不是函数定义的位置.
在此代码中调用"generateScale"方法的情况下,它是调用设置上下文的generateScale函数的点符号.换句话说,因为代码读取prototype.generateScale,函数调用的上下文("this"关键字)被设置为prototype对象,这恰好是Graph构造函数的原型.
由于Graph.prototype现在是调用的上下文generateScale,该函数将运行您期望的上下文和行为.
相反,当您进行调用时this.constructor._super.generateScale,您允许JavaScript以您不期望的方式扭曲上下文,因为this开头的关键字.
这是您的层次结构的第3级导致"this"的问题.你正在调用EUG.generateScale,它明确地设置this为EUG实例.该generateScale方法的原型查找返回Graph原型以调用该方法,因为该方法未EUG直接在实例上找到.
但是this已经设置了EUG实例,并且JavaScript的原型查找受到尊重this.因此,当generateScale调用UsageGraph原型时,this将设置为EUG实例.因此,调用this.constructor.__super__将从EUG实例进行评估,并将找到UsageGraph原型作为值__super__,这意味着您将在同一对象上调用相同的方法,并再次使用相同的上下文.因此,一个无限循环.
该解决方案不适用于this原型查找.正如我在解决方案和JSFiddle中所展示的那样,直接使用命名函数和原型.
到目前为止,我最好的解决方案是命名该方法的函数,以便能够直接引用它并将其与所谓的“父”方法进行比较,这感觉非常糟糕且无法扩展 - 也许这是我第一次发现它的用途给方法一个单独的函数名称。欢迎提出任何意见或改进;
Graph = function () {};
Graph.extend = myExtendFunction;
Graph.prototype = {
generateScale: function GS() {
//do stuff
}
}
// base class defined elsewhere
UsageGraph = Graph.extend({
generateScale: function GS() {
var parentMethod = this.constructor._super.generateScale;
if(parentMethod === GS) {
parentMethod = this.constructor._super.constructor._super.generateScale;
}
parentMethod.call(this); // run the parent's method
//do additional stuff
}
})
ExcessiveUsageGraph = Graph.extend({
// some methods, not including generateScale, which is inherited directly from Usage Graph
})
var EUG = new ExcessiveUsageGraph();
EUG.generateScale(); // infinite loop
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1318 次 |
| 最近记录: |