javascript继承奇异性

javascript继承奇异性,javascript,inheritance,Javascript,Inheritance,为什么下面的“Cat.prototype=new哺乳类()”行在Cat()函数内部不起作用,但在Cat()函数外部起作用 function Mammal() { Mammal.prototype.hasHair = function() { return true; } } alert( new Mammal().hasHair() ); // dispays true here function Cat() { Cat.prototype = new Mammal(); } tr

为什么下面的“Cat.prototype=new哺乳类()”行在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的函数中定义Cat,而不是到处传播。

因为
原型
成员在执行构造函数之前被传递到对象实例


因此,上面的代码可以工作,但是如果您首先注释了
newcat()行它不会,因为在
new Cat().hasHair()
行上,Cat的原型没有
hasHair()
方法,因为
prototype
成员在执行构造函数之前被传递到对象实例


因此,上面的代码可以工作,但是如果您首先注释了
newcat()行它不会,因为在
新的Cat().hashiir()
行上,Cat的原型没有
hashiir()
方法

我有点困惑。你到底期望什么

您正在将一个函数从
Cat
分配到原型链中,但您是在调用构造函数时这样做的。如果像
new Cat().hasHair()
那样调用它,则调用对象根本不知道该函数


在实际调用构造函数之前,需要扩展
.prototype

我有点困惑。你到底期望什么

您正在将一个函数从
Cat
分配到原型链中,但您是在调用构造函数时这样做的。如果像
new Cat().hasHair()
那样调用它,则调用对象根本不知道该函数


在实际调用构造函数之前,需要扩展
.prototype

函数的原型(充当类)是创建新对象时复制的对象。您不应该在构造函数中设置原型的属性

或者:

function Mammal() {
}
Mammal.prototype.hasHair = function(){ return true };
或者这个:

function Mammal() {
    this.hasHair = function(){ return true }
}

函数(作为类)的原型是创建新对象时从中复制的对象。您不应该在构造函数中设置原型的属性

或者:

function Mammal() {
}
Mammal.prototype.hasHair = function(){ return true };
或者这个:

function Mammal() {
    this.hasHair = function(){ return true }
}

我编辑了你的代码,所以它可以实现你的目标。下面的代码创建一个基类,然后创建一个子类,其样式与您尝试创建基类的样式相同

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
}

我编辑了您的代码,以便它能够实现您的目标。下面的代码创建一个基类,然后创建一个子类,其样式与您尝试创建基类的样式相同

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
}

在执行
new Cat
时,将创建一个从
Cat.prototype
继承的空对象。什么是
Cat.prototype
?它是一个空对象,因为您尚未修改它

在构造器内部,您正在分配
Cat.prototype=new demal()
Cat
的下一个实例将继承自此
哺乳动物
实例。但是,创建第二个实例也将创建另一个
哺乳动物
实例,第三个
实例从中继承,依此类推

您最终得到了这个继承链(
catX
Cat
的第x个实例,
malemax
malemal
的第x个实例):

每个
Cat
实例都有自己的原型,这在某种程度上与原型的用途相反(共享公共代码)。这看起来可能没什么大不了的,但它有几个后果,包括:

  • 增加内存使用:(几乎)每个
    Cat
    实例都有一个对应的
    哺乳动物
    实例,因此您有
    2N
    对象,而不是
    N+1
  • 继承测试中断:
    instanceof
    通过比较原型来工作,并且由于
    cat0
    的原型不同于
    Cat.prototype
    (创建多个实例后),
    Cat
    的实例将产生
    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;

Object.create
创建从作为参数传递的对象继承的对象。请参阅。

在执行
新Cat
时,将创建一个从
Cat.prototype
继承的空对象。什么是
Cat.prototype
?它是一个空对象,因为您尚未修改它

在构造器内部,您正在分配
Cat.prototype=new demal()
Cat
的下一个实例将继承自此
哺乳动物
实例。但是,创建第二个实例也将创建另一个
哺乳动物
实例,第三个
实例从中继承,依此类推

您最终得到了这个继承链(
catX
Cat
的第x个实例,
malemax
malemal
的第x个实例):

每个
Cat
实例都有自己的原型,这在某种程度上与原型的用途相反(共享公共代码)。这看起来可能没什么大不了的,但它有几个后果,包括:

  • 增加内存使用:(几乎)每个
    Cat
    实例都有一个对应的
    哺乳动物
    实例,因此您有
    2N
    对象,而不是
    N+1
  • 继承测试中断:
    instanceof
    function Cat() {
    }
    Cat.prototype = new Mammal();
    new Cat().hasHair();