这是我的父类(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
可以在其中生活而不会打扰任何人。此外,创建了两个名为 setName
和 getName
的新函数,并绑定(bind)到 Select
的 prototype
对象。
从现在开始,如果您创建一个新的 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)是一种用于创建实例的模板。了解这一点并考虑您的代码,我们至少可以做出两个观察:
- 如您所知,构造函数旨在初始化实例。在您的情况下,初始化过程 -
Element
中的内容 - 不必要地执行,因为当前的目标是设置将在其上创建实例的模板。 - 假设
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/