javascript - JS继承的诡异时刻

标签 javascript prototype prototypal-inheritance

这是我的父类(super class):

function Element() {
   var name;
   this.setName(n) = func()...{};
   this.getName() = func()..{return name};
}

我的另一个子类:

Select = null;
...
Select =
   function (n) {
       if (typeof n !== "undefined")
          this.setName(n);
   ...
}
Select.prototype = new Element();
Select.prototype.constructor = Select;

那么,我说的是哪种“怪异时刻”?在这里:

var e1 = new Select("element1");
e1.getName();  // return "element1"
var e2 = new Select();  // WITHOUT NAME
e2.getName();  // return "element1"!!! should be ""!

这是一个相当可预测的行为,但如何解决这个问题呢? 当然,我可以在 Element 中制作类似 this.clear() 的东西,它将清除属性并将此方法放入 Select 函数中,但也许有一个合适的解决方案?

最佳答案

您应该将此行 Element.call(this, n) 添加到 Select 中。这很难解释,我很生气,因为我不喜欢 javascript 中的假私有(private)属性,但是,我必须提供一些细节,以便您了解您当前在做什么,否则我将无法到达 sleep 。

因此,执行 new Element() 会创建一个新的上下文,name 可以在其中生活而不会打扰任何人。此外,创建了两个名为 setNamegetName 的新函数,并绑定(bind)到 Selectprototype 对象。

从现在开始,如果您创建一个新的 Select 实例,您就可以调用这些函数,因为它们在实例的原型(prototype)中可用。这实际上是在执行 new Select("element1") 时发生的。事实上,n 已被定义,因此,setName 是从 this 调用的,它引用了实例。

但最重要的是,调用 setName 并将 n 设置为 "element1" 也会将 name 设置为 “元素1”。然后,如果您创建 Select 的第二个实例,而没有定义 n,则不会调用 setName,因此,name 仍然设置为 "element1"对于这两个实例

为什么对于这两种情况?因为这两个实例共享相同的 setName 方法,绑定(bind)到原型(prototype)的方法,并且此方法引用唯一的 name 变量 - 请记住 Element只被调用一次。

最后,为什么这个新行 Element.call(this, n) 会阻止 name 被共享?因为每次调用Element都会创建一个新的上下文,也就是说,一个新的name,一个新的setName和一个新的getName ,并将这两个方法绑定(bind)到新创建的实例。

好吧,希望今天是你的早晨,如果你因为我的错而陷休眠眠障碍,我会很抱歉......


Bergi 所述和 HMR ,这种创建原型(prototype)的方式 - Child.prototype = new Parent - 已经过时并且会把你带到死胡同。请记住,原型(prototype)是一种用于创建实例的模板。了解这一点并考虑您的代码,我们至少可以做出两个观察:

  1. 如您所知,构造函数旨在初始化实例。在您的情况下,初始化过程 - Element 中的内容 - 不必要地执行,因为当前的目标是设置将在其上创建实例的模板。
  2. 假设 new Element(name) 中需要 name,否则您的程序会崩溃。你会给原型(prototype)取什么样的名字?这个问题显然没有用,因为您不想给模板命名。

要绕过这些问题,您需要一个中间人,如下面的代码所示(复制自 Bergi 分享的 link)。如您所见,原型(prototype)的创建被委托(delegate)给一个空的“虚拟”构造函数。这样做可以解决上面提出的两个问题。

function Dummy () {}
Dummy.prototype = Element.prototype;
Select.prototype = new Dummy();
Select.prototype.constructor = Select;

或者,您可以使用内置的 Object.create() :

Select.prototype = Object.create(Element.prototype);
Select.prototype.constructor = Select;

进一步阅读:

关于javascript - JS继承的诡异时刻,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21714707/

相关文章:

javascript - Coffeescript-Javascript 关联

javascript - jQuery $.getJSON 对每个控件只工作一次。不再到达服务器

javascript - 如何通过字段转换器对 xPage 多行编辑框进行排序?

javascript - 在 JavaScript 中创建派生类的多个实例

javascript - 在原型(prototype)上定义方法

javascript:调用基类函数

Javascript 使用 Object.create 和属性指针未从原型(prototype)中取消引用

javascript - 复制粘贴在 Firefox 后数字验证的文本框中不起作用

javascript - 超时后在 svg.node() 上调用 d3.mouse

javascript 数组原型(prototype) - 添加了新方法 - 奇怪的 console.log