【问题标题】:Javascript prototype inheritance and "instanceof"Javascript原型继承和“instanceof”
【发布时间】:2020-11-10 19:57:41
【问题描述】:

我只是不明白,为什么在对象继承中“instanceof”无法将“子”对象评估为父原型的实例。例如:

function Parent(property) {
    this.property = property;
}

function Child(property) {
    Parent.call(property);
}

const child = new Child("");

console.log(child instanceof Child); // of course, true
console.log(child instanceof Parent); // false. But why???

至于类的继承(或者更确切地说是JS中的类),情况就不同了:

class Parent {
    constructor(property) {
        this.property = property;
    }
}

class Child extends Parent {
    constructor(property) {
        super(property);
    }
}

const child = new Child("");

console.log(child instanceof Child); // true
console.log(child instanceof Parent); // also true!!!

造成这种差异的原因是什么?是否可以创建子对象,以便正确地将它们识别为父原型的实例(无需借助类)?

【问题讨论】:

  • 你的第一个例子没有使用原型继承,这就是原因。

标签: javascript object inheritance


【解决方案1】:

您的第一个示例很简单,与“原型继承”在 Javascript 中的工作方式相差甚远。

一方面,Parent.call(property) 肯定不是您的意思。这会调用Parent 并将其this 设置为property,并且没有传递任何参数,这绝对不是您想要的。我怀疑你的意思是 Parent.call(this, property) - 它调用 Parent 与传递给 Childthis 相同,并通过 property 参数。但这与“继承”无关。

instanceof 运算符只是检查对象的“原型链”以查看相关对象(您正在测试的“类”的prototype 属性)是否出现在任何地方。操作对象以影响instanceof 运算符的唯一方法是更改​​原型链。

有很多方法可以做到这一点,但是在 ES6 之前的 JS 中“伪造”诸如基于类的继承之类的标准方法是这样的:

function Parent(property) {
    this.property = property;
}

function Child(property) {
}

Child.prototype = Object.create(Parent.prototype);

const child = new Child("");

console.log(child instanceof Child);
console.log(child instanceof Parent);

它手动使从Child 构造的所有对象委托给Object.create(Parent.prototype)Object.create(Parent.prototype) 本身就是一个从Parent.prototype“继承”的对象(否则完全为空且没有特殊属性)。所以现在当instanceof检查原型链时,它找到了它正在寻找的东西,因此返回true,从上面的sn-p可以看出。

当然,如果你真的想在 JS 中实现基于类的继承(我个人不推荐,但肯定很受欢迎),ES6 class 语法提供了更好的语法糖,所以你没有如上所述手动弄乱原型链。但请注意,这基本上是 ES6 类“幕后”发生的事情。

我强烈推荐this 书(可免费在线阅读)以获得更深入的解释。在这种情况下,第 5 章是最相关的。

【讨论】:

  • 非常感谢您提供 100% 翔实且清晰的答案!你帮了我很多。
  • 是否可以使用“Object.setPrototypeOf(Child.prototype, Parent.prototype);”而不是“Child.prototype = Object.create(Parent.prototype);” (在你的例子中)?我试过了,它有效。区别如下:当我使用“setPrototypeOf”然后在控制台“Object.getOwnPropertyNames(Child.prototype)”中检查时,我可以看到里面的构造函数属性,但是当我使用“Object.create”时(比如在您的示例中),此检查不显示构造函数。
  • 很抱歉再次打扰您...但是为什么使用“Object.setPrototypeOf(Child.prototype, Parent.prototype);”的结果是不同的。 "和“Child.prototype = Object.create(Parent.prototype);”?见上文(我刚刚编辑了评论)。
  • "Object.setPrototypeOf(Child.prototype, Parent.prototype);"似乎与“Child.prototype.__proto__ = Parent.prototype;”相同,但与“Child.prototype = Object.create(Parent.prototype);”不同:在前两种情况下,构造函数显示何时检查"Object.getOwnPropertyNames(Child.prototype)";在第三种情况下, Child 似乎失去了自己的构造函数属性......
  • 那是因为 JS 自动为你创建的Child.prototype 包含一个constructor 属性。前两个示例只是更改了该对象的原型,而带有Object.create 的示例完全覆盖了该对象(使用正确的原型创建了一个完全空的对象)。
猜你喜欢
  • 1970-01-01
  • 2013-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 2010-09-28
  • 2018-02-21
相关资源
最近更新 更多