我正在使用从 Backbone 改编而来的扩展函数(除了为符合我雇主的命名约定而进行的一些更改外,它们完全相同)来实现原型(prototype)继承。设置以下结构后(下面大大简化)我得到一个无限循环。
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
循环发生是因为 ExcessiveUsageGraph
沿着原型(prototype)链向上移动到 UsageGraph
来运行该方法,但是 this
仍然设置为一个实例ExcessiveUsageGraph
所以当我使用 this.constructor._super
运行父方法时,它也向上移动到 UsageGraph
并调用同样的方法。
如何从 Backbone 风格的原型(prototype)中引用父方法并避免这种循环。如果可能,我还想避免按名称引用父类。
编辑 Here's a fiddle demonstrating that this happens in Backbone
最佳答案
您遇到了 JavaScript 的 this
和原型(prototype)继承的局限性之一,这完全是因为您试图用一种不直接支持的语言创建类继承方案
即使使用 Backbone,通常也不鼓励您直接使用“super”,因为您概述的限制等等。
解决问题
常见的解决方案是直接调用原型(prototype)对象,而不是试图通过使用“ super ”引用来掩盖它。
UsageGraph = Graph.extend({
generateScale: function () {
Graph.prototype.generateScale.call(this); // run the parent's method
//do additional stuff
}
})
在工作的 JSFiddle 中:http://jsfiddle.net/derickbailey/vjvHP/4/
之所以有效,与 JavaScript 中的“this”有关。当你调用一个函数时,“this”关键字是根据你调用函数的方式设置的,而不是函数定义的位置。
在这段代码中调用“generateScale”方法的情况下,它是调用设置上下文的 generateScale 函数的点符号。换句话说,因为代码读取 prototype.generateScale
,函数调用的上下文(“this”关键字)被设置为 prototype
对象,这恰好是Graph
构造函数的原型(prototype)。
由于 Graph.prototype
现在是调用 generateScale
的上下文,该函数将以您期望的上下文和行为运行。
为什么 this.constructor.super 失败了
相反,当您调用 this.constructor._super.generateScale
时,由于 this<,您允许 JavaScript 以您没有预料到的方式扭曲上下文
开头的关键字。
导致“this”问题的是层次结构的第 3 级。您正在调用 EUG.generateScale
,它明确地将 this
设置为 EUG
实例。 generateScale
方法的原型(prototype)查找返回到 Graph
原型(prototype)以调用该方法,因为该方法未直接在 EUG
实例上找到.
但是 this
已经被设置为 EUG
实例,并且 JavaScript 的原型(prototype)查找尊重 this
。因此,当 UsageGraph 原型(prototype) generateScale
被调用时,this
被设置为 EUG
实例。因此,调用 this.constructor.__super__
将从 EUG
实例进行评估,并将找到 UsageGraph 原型(prototype)作为 __super__
,这意味着您将再次使用相同的上下文在相同的对象上调用相同的方法。因此,一个无限循环。
解决方案是不要在原型(prototype)查找中使用this
。直接使用命名函数和原型(prototype),如我在解决方案和 JSFiddle 中所示。
关于javascript - 使用 Backbone 样式的原型(prototype)继承时防止无限递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10008285/