首页 > 解决方案 > 为什么我在“console.log”对象时看不到从父对象继承的那些属性;在javascript中

问题描述

大家好,我最近正在学习 JavaScript 中的继承。我创建一个Child函数并使其继承该Human函数。我为then创建一个child实例。Childconsole.log(child)

我想知道为什么输出只有属性Child,但没有Human属性。

我想这是因为属性描述符,特别是enumerable,但我无法弄清楚。谁能帮我?

const Child = function() {
  this.name = "child"
}

const Human = function() {
  this.move = "walking";
}

Child.prototype = new Human();
Child.prototype.constructor = Child;

const child = new Child();
console.log(child);

运行上面的代码后,我只看到 {name: "child"},虽然console.log(child.move)给出了'walking'。

标签: javascriptinheritance

解决方案


简短的回答是,move在实例上找不到Child,而是在它继承自的原型上找到Human

让我们分析一下您的代码。

const Child = function() {
  this.name = "child"
}

const Human = function() {
  this.move = "walking";
}

这些是不言自明的,您创建了两个构造函数。它们是无关的(还)。

Child.prototype = new Human();
Child.prototype.constructor = Child;

这是继承部分。Child.prototype = new Human();将创建 的实例Human,并将其分配给Child.prototype,因为该实例有一个成员move,该成员被分配给Child.prototype并且您得到本质上的Child.prototype = { move: 'walking' }Child.prototype.move = 'walking'(那些不准确,但足够接近)

然后你将Child自己指定为prototype.constructor.


您看到奇怪行为的原因是您希望move成为实例成员,但它是原型成员。这种效果的一个更显着的缺点是更改child.move会同时针对所有子实例更改它,这不是您对实例成员的期望。

出于这个原因,不建议通过实际创建实例来进行继承,就像你做的那样,而是使用Object.create(),像这样:

Child.prototype = Object.create(Human.prototype);
Child.prototype.constructor = Child;

此外,您的Child函数应该调用父构造函数,以维护父的逻辑和成员。像这样:

const Child = function() {
  Human.call(this); // call to parent constructor
  this.name = "child";
}

完整代码:

const Human = function() {
  this.move = "walking";
}
const Child = function() {
  Human.call(this);
  this.name = "child"
}
Child.prototype = Object.create(Human.prototype);
Child.prototype.constructor = Child;

const child = new Child();
console.log(child);


一旦你理解了原型链是如何工作的,请记住创建 ES6 类是为了更优雅地处理这些情况并使用更易读的代码:

class Human {
  constructor() {
    this.move = "walking";
  }
}

class Child extends Human {
  constructor() {
    super();
    this.name = "child";
  }
}

推荐阅读