为什么下面的“Cat.prototype = new Mammal()”行在Cat()函数内部不起作用,但它在Cat()函数之外工作?
function Mammal() {
Mammal.prototype.hasHair = function() { return true; }
}
alert( new Mammal().hasHair() ); // dispays true here
function Cat() {
Cat.prototype = new Mammal();
}
try {
new Cat().hasHair(); // doesn't work. why?
} catch ( err ) {
alert('error'); // displays error here
}
Cat.prototype = new Mammal(); // same line as inside Cat() function
alert( new Cat().hasHair() ); // now it works
我尝试了几个不同的javascript实现,所以我怀疑它是一个实现特性。我很想知道这主要是出于好奇,但也仅仅是为了组织,我想在Cat的功能中定义Cats,而不是遍布各处。
答案 0 :(得分:2)
执行new Cat
时,会创建一个继承自Cat.prototype
的空对象。什么是Cat.prototype
?它是一个空对象,因为你尚未修改它。
在构造函数中,您正在分配Cat.prototype = new Mammal();
。 Cat
的下一个实例将从此Mammal
实例继承。虽然创建第二个实例也会创建另一个Mammal
实例,第三个Cat
实例从该实例继承,依此类推。
您最终拥有此继承链(catX
是Cat
的第x个实例,而mammalX
是Mammal
的第x个实例):
cat0 -> Object
cat1 -> mammal0 -> Mammal.prototype
cat2 -> mammal1 -> Mammal.prototype
...
每个Cat
实例都有自己的原型,这与原型用于(共享公共代码)有些相反。它可能看起来不是什么大问题,但它有几个后果,包括:
Cat
实例都有一个对应的Mammal
实例,因此您拥有2N
个对象而不是N + 1
。instanceof
通过比较原型来工作,并且由于cat0
的原型与Cat.prototype
不同(创建多个实例后),cat instanceof Cat
将产生{ {1}}。您真正想要的继承链是:
false
永远不要在构造函数中为原型(或覆盖原型)赋值。构造函数应该只设置特定于实例的属性(在某些情况下,您可能希望更改静态属性,但这些属性不太常见)。
在构造函数外部设置原型:
cat0 -> Mammal.prototype
cat1 -> Mammal.prototype
cat2 -> Mammal.prototype
...
function Mammal() {}
Mammal.prototype.hasHair = function() { return true; }
function Cat() {
Mammal.apply(this, arguments);
}
Cat.prototype = Object.create(Mammal.prototype);
Cat.prototype.constructor = Cat;
创建一个继承自您作为参数传递的对象的对象。请参阅MDN。
答案 1 :(得分:1)
因为在构造函数执行之前将prototype
成员传递给对象实例。
function Mammal() {
Mammal.prototype.hasHair = function() { return true; }
}
function Cat() {
Cat.prototype = new Mammal();
}
new Cat();
alert(new Cat().hasHair());
因此上面的代码可以使用,但是如果你评论了第一个new Cat();
行,那么就不会在new Cat().hasHair()
行上找到Cat的原型没有hasHair()
方法
答案 2 :(得分:0)
我有点困惑。你到底想要什么?
您正在从Cat
将函数分配到原型链中,但您需要调用构造函数。如果您将其称为new Cat().hasHair()
,则调用对象根本不了解该功能。
在实际调用构造函数之前,需要扩展.prototype
。
答案 3 :(得分:0)
函数的原型(作为一个类)是新对象在创建时复制的对象。您不应该在构造函数中设置原型的属性。
要么:
function Mammal() {
}
Mammal.prototype.hasHair = function(){ return true };
或者这个:
function Mammal() {
this.hasHair = function(){ return true }
}
答案 4 :(得分:0)
我编辑了您的代码,以便实现您的目标。下面的代码创建一个基类,然后创建一个与您尝试执行它的样式相同的子类。
function Mammal() {
this.hasHair = function() { return true; }
}
alert( new Mammal().hasHair() ); // dispays true here
function Cat() {
Mammal.call(this);
}
try {
alert( new Cat().hasHair() ); // dispays true here
} catch ( err ) {
alert('error'); // should not fire
}
答案 5 :(得分:0)
因为你在每个实例化时都要覆盖原型。 Javascript实际上没有继承。
当你做
时function Mammal() {
Mammal.prototype.hasHair = function() { return true; }
}
new Mammal().hasHair();
意味着
Mammal
作为构造函数并实例化new Mammal
类型对象Mammal
的原型但如果你这样做:
function Cat() {
}
Cat.prototype = new Mammal();
new Cat().hasHair();
意味着
Cat
构造函数的原型为new Mammal type object
new Cat type object
'类'hasHair()
方法的Mammal
醇>
希望这会有所帮助。