javascript - 使用 Backbone 样式的原型(prototype)继承时防止无限递归

标签 javascript inheritance backbone.js prototypal-inheritance

我正在使用从 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/

相关文章:

javascript - 将预加载器移出 main.js 主干

javascript - 具有后端授权的 JavaScript 安全模式?

javascript - Backbone & Require - 离开时破坏 View

javascript - 在浏览器中停止处理时如何停止进度 gif 图像

c# - .net 中的存储库模式和继承

javascript - 相当于使用 __proto__?

generics - 表达继承的不同符号

javascript - Chrome 扩展程序事件页面对于某些页面是否持久?

javascript - 无法运行下载的 Angular 项目

javascript - 想知道 html 表单在 firefox 中的行为吗?