我一直在试验原型继承,如下面的代码片段所示。在父级原型上设置属性
function extend(c, p) {
function f() { this.constructor = c; }
f.prototype = p.prototype;
c.prototype = new f();
}
function Parent() {}
function Child() {}
extend(Child, Parent);
var p = new Parent();
var c = new Child();
// Child.prototype.say = function() { alert("child"); };
Parent.prototype.say = function() { alert("parent"); };
p.say();
c.say();
运行此脚本时,会显示两条警报显示parent
。
但是,如果我取消对注释行的注释,则第一个警报显示parent
,而第二个显示child
。
乍一看,这是非常意外的。看起来Parent.say
将覆盖Child.say
,因为它稍后设置。
从我的理解,因为Child.prototype
是一个对象,而f
一个实例,在这个原型设置的所有属性上直接设置的f
该特定实例的实例。
当调用c.say
,将发生以下情况:
如果
say
直接设置c
,调用它。它不会直接在实例上设置,因此,请跳至2.在
Children.prototype
中查找say
,f
的实例。再次查找直接在f
实例上设置的属性。如果该行是未注释,则在此处找到say
,并停止搜索。查找
say
在f.prototype
,这是Parent.prototype
。这是发现say
的地方,当时线路仍然为评论了。
问:我才明白正确的JavaScript如何查找财产?如果是这种情况,那么可以解释为什么子行不是,如果该行未被注释,则由父属性重写。
有道理。现有实例受到影响的原因是实例的原型和构造函数的原型仍然保持相同的对象。 – afsantos
@afsantos:对,它们都指向同一个对象,因此通过这两个引用向该对象添加属性。 –
非常棒的答案!对于ASCII艺术的奖励点,应该有一个工具来自动说明这些事情。 – afsantos