Javascript原型继承和“instanceof”

Rom*_*din 1 javascript inheritance object

我只是无法理解,为什么在对象继承中“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???
Run Code Online (Sandbox Code Playgroud)

至于类的继承(或者说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!!!
Run Code Online (Sandbox Code Playgroud)

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

Rob*_*ond 6

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

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

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

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

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);
Run Code Online (Sandbox Code Playgroud)

它手动使所有对象从Childdelegate 构造为Object.create(Parent.prototype),它本身就是一个“继承”自 的对象(否则完全是空的并且没有特殊属性)Parent.prototype。因此,现在当instanceof检查原型链时,它会找到它正在寻找的内容,因此返回true,正如您从上面的代码片段中看到的那样。

当然,如果你确实想要在 JS 中基于类的继承(我个人不推荐,但肯定很流行),ES6 语法class提供了更好的语法糖,因此你不必手动弄乱原型链如上。但请注意,这本质上就是 ES6 类“幕后”发生的事情。

我强烈推荐本书(可以免费在线阅读),以获得对这一切的更深入的解释。第 5 章是与此背景最相关的章节。