为什么在使用 Object.setPrototypeOf 时 super() 调用了错误的构造函数?

问题描述 投票:0回答:1

我有以下代码:

class Polygon {
  constructor() {
    this.name = "Polygon";
  }
}

class Rectangle {
  constructor() {
    this.name = "Rectangle";
  }
}

class Square extends Polygon {
  constructor() {
    super(); 
  }
}

Object.setPrototypeOf(Square, Rectangle);

const instance = new Square();

console.log(instance.name); // Rectangle

我的理解是:

  • Instance__proto__
    :指向Square.prototype继承实例方法。
  • Subclass.__proto__
    :指向 Rectangle 继承静态方法和属性。
  • Square.prototype.__proto__
    :指向Polygon.prototype继承父类的实例方法。

我的问题:

在上面的代码中,使用

Object.setPrototypeOf(Square, Rectangle)
后,
Square._proto_
现在所有静态属性都指向矩形而不是多边形。为了继承所有其他方法,
Square.prototype._proto_
指向
Polygon.prototype
。因此,我期望 Square 中的
super()
调用 Polygon 的构造函数,因为 Square 扩展了 Polygon。然而,似乎 super() 正在调用 Rectangle 的构造函数。我现在很困惑,当
Object.setPrototypeOf(Square, Rectangle)
运行时,一切都发生了变化,似乎我的理解存在差距。

javascript class inheritance prototype
1个回答
0
投票

我将省略有关类、原型等的大部分细节 - 您可以在 MDN 的 object prototypesclasses 页面上阅读有关它们的信息。

但是:一般来说,在 JS 中,

class
并不像其他语言那样预先支持。 JS 允许在运行时改变类的定义,因此对super()的调用可以在整个脚本执行过程中指向
不同的
构造函数如果你愿意的话。从这一点来看,它更像是 Common Lisp 中的类,而不是 Java 中的类。 当你写作时

class Square extends Polygon { // ... elided ... }

它在概念上
与你所写的

相同 function Square() {} Square.prototype = Polygon.prototype;

所以当你写作时

Object.setPrototypeOf(Square, Rectangle);

它可以(再次从概念上)翻译成

Square.prototype = Rectangle.prototype;

这意味着当时

super();

执行后,它指向 Square 实例上下文中的
Rectangle.prototype.constructor()
。因此,你最终会得到

this.name

 成为 
"Rectangle"
	

© www.soinside.com 2019 - 2024. All rights reserved.