You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

获取原型链中对象名称:JavaScript原型继承输出异常排查

问题分析与解决方案

为什么会得到Animal、Animal、Animal、Object的输出?

核心问题出在你设置Cat原型的方式和constructor属性的指向错误:

  1. 当你执行Cat.prototype = new Animal();时,你把Cat的原型对象替换成了一个Animal的实例。这个Animal实例的constructor属性默认指向Animal构造函数(因为所有Animal实例的原型链都会指向Animal.prototype,而Animal.prototype.constructor默认是Animal)。
  2. 当你访问cat1.constructor时,因为cat1本身没有constructor属性,会顺着原型链查找,找到Cat的原型(那个Animal实例)的constructor,也就是Animal。
  3. 接下来的循环中:
    • 第一个currentPrototype是cat1,输出Animal;
    • 第二个currentPrototype是cat1的原型(Animal实例),它的constructor还是Animal;
    • 第三个currentPrototype是Animal.prototype,它的constructor默认就是Animal;
    • 最后到Object.prototype,输出Object。

这就导致了你看到的重复Animal输出。

你的原型继承写法存在哪些问题?

用new Animal()作为子类的原型是一种过时且有缺陷的写法:

  • 会不必要地执行父类的构造函数,导致父类构造函数中定义的实例属性(比如name、age、eat、getAge)被加到子类的原型上,这些属性应该属于子类实例,而不是原型;
  • 子类原型的constructor属性没有修正,导致实例的constructor指向错误,无法正确反映实例的构造函数类型;
  • 每个实例都会创建独立的eat、getAge、hunt函数,浪费内存(这些方法应该放到原型上共享)。

如何修正代码得到正确结果?

我们需要用更规范的原型继承方式,同时修正constructor指向:

修正后的完整代码:

function Animal(name, age){
 this.name = name;
 this.age = age;
}
// 将方法放到原型上,让所有实例共享
Animal.prototype.eat = function(){
 console.log(this.name + " eats");
};
Animal.prototype.getAge = function(){
 console.log(this.name + " is " + this.age + " years old");
};

function Cat(name, age){
 // 调用父类构造函数,初始化实例属性
 Animal.call(this, name, age);
}
// 用Object.create创建以Animal.prototype为原型的对象,避免执行父类构造函数
Cat.prototype = Object.create(Animal.prototype);
// 手动修正constructor指向,让Cat实例的constructor回到Cat
Cat.prototype.constructor = Cat;
// 给Cat添加独有的原型方法
Cat.prototype.hunt = function(){
 console.log(this.name + " hunts mice");
};

var cat1 = new Cat("cat1", 2);
var currentPrototype = cat1;
while(currentPrototype != null){
 console.log(currentPrototype.constructor.name);
 currentPrototype = Object.getPrototypeOf(currentPrototype);
}

修正后的输出:

Cat
Animal
Object

关键修正点说明:

  1. Object.create(Animal.prototype):创建一个空对象,其原型直接指向Animal.prototype,不会执行Animal的构造函数,避免了父类实例属性污染子类原型的问题。
  2. Cat.prototype.constructor = Cat:因为Object.create创建的对象默认constructor是Object,所以必须手动修正回Cat,这样实例的constructor才能正确指向自己的构造函数。
  3. 将方法移到原型上:所有实例共享同一个方法,节省内存,这是原型继承的最佳实践。

内容的提问来源于stack exchange,提问作者KGS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:36:51