我有以下代码:
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)
运行时,一切都发生了变化,似乎我的理解存在差距。
我将省略有关类、原型等的大部分细节 - 您可以在 MDN 的 object prototypes 和 classes 页面上阅读有关它们的信息。
但是:一般来说,在 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();
Rectangle.prototype.constructor()
。因此,你最终会得到 this.name
成为
"Rectangle"
。