У меня есть следующий код:
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.info(instance.name); // Rectangle
Мое понимание:
Instance__proto__: Указывает на Square.prototype для наследования методов экземпляра.Subclass.__proto__: Указывает на Rectangle для наследования статических методов и свойств.Square.prototype.__proto__: указывает на Polygon.prototype для наследования методов экземпляра родительского класса.Мой вопрос:
В приведенном выше коде после использования Object.setPrototypeOf(Square, Rectangle)Square._proto_ теперь указывает на Rectangle, а не на Polygon для всех статических свойств. А для наследования всех остальных методов Square.prototype._proto_ указывает на Polygon.prototype. Итак, я ожидаю, что super() в Square вызовет конструктор Polygon, поскольку Square расширяет Polygon. Однако похоже, что super() вместо этого вызывает конструктор Rectangle. Теперь я в замешательстве: что все меняется при запуске Object.setPrototypeOf(Square, Rectangle), похоже, в моем понимании есть пробел.
См. Сопоставляется ли super() с __proto__ под капотом?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Чего не хватает, так это того, откуда берется значение super.
Базовый класс (то есть не расширяющий другой класс) создается на Function.prototype. Например
Object.getPrototype(Polygon) === Function.prototype
Класс, расширяющий другой, приводит к двум вещам:
Объект расширенного класса создается на основе расширяемого класса, а не на Function.prototype. Например
Object.getPrototypeOf(Square) === Polygon
Свойство prototype расширенного класса создано на основе свойства prototype расширенного класса. Например
Object.getPrototypOf(Square.prototype) === Polygon.prototype
Обратите внимание, что значение constructor, унаследованное от prototype расширенного класса, не изменяется и остается установленным для объекта расширенного класса. И.Е.
Square.prototype.constructor === Square
Это имеет последствия: суперкласс расширенного объекта не может быть определен на основе свойства constructor, унаследованного экземплярами расширенного класса.
super для поиска метода конструктора объекта суперкласса.Этот код показывает последствия изменения объекта, на котором создан прототип объекта класса, в экспериментальных целях, чтобы увидеть, что произойдет. Это не то, что нужно делать в реальном программировании.
class Polygon {
static ClassName = "Polygon";
constructor() { this.name = "Polygon instance" }
inheritsFrom() {return "Polygon"}
}
class Rectangle {
static ClassName = "Rectangle";
constructor() { this.name = "Rectangle instance"; }
inheritsFrom() {return "Rectangle"}
}
class Square extends Polygon {
constructor() {
super();
}
}
console.info("class Polygon is prototyped on Function.prototype: ",
Object.getPrototypeOf(Polygon) === Function.prototype, " (1) true expected");
console.info(Square.ClassName, " (2) static value 'Polygon' expected");
const instance = new Square();
console.info( instance.name, " (3) 'Polygon instance' expected")
console.info( instance.constructor.name, " (4) 'Square' expected")
// overwrite the object (the super class) on which Square is prototyped:
Object.setPrototypeOf(Square, Rectangle);
console.info( Square.ClassName, " (5) static value 'Rectangle' expected");
const instance2 = new Square();
console.info(instance2.name, " (6) 'Rectangle instance' expected");
console.info( instance2.constructor.name, " (7) 'Square' expected")
// instances of Square still inherit from Polygon.prototype
console.info("instance instanceof Polygon is ", instance instanceof Polygon,
" (8) true expected");
console.info("instance instanceof Rectangle is ",
instance instanceof Rectangle, " (9) false expected)");
console.info("instance inherits from ", instance.inheritsFrom(), " (10) 'Polygon' expected");
console.info("instance2 is an instanceOf Polygon ", instance2 instanceof Polygon,
" (11) true expected");
console.info("instance2.instanceof Rectangle is ",
instance2 instanceof Rectangle, " (12) false expected");
console.info("instance2 inherits from ", instance2.inheritsFrom(),
" (13) 'Polygon' expected");Обновление: использование __proto__ в качестве унаследованного метода получения для возврата значения null или объект, для которого был прототипирован другой объект, был помечен как «НОРМАТИВНЫЙ ДОПОЛНИТЕЛЬНЫЙ, СТАРЫЙ» в ECMAScript и, следовательно, считается устаревшим: использование __proto__ было удален из тестового кода.
Во всем вышеперечисленном
Polygon и Rectangle в тестовом коде объявляют статическое свойство ClassName и метод класса с именем inheritsFromClassName наследуется Square от объекта, для которого Square был создан прототип в момент Square.ClassName оценки.name — это свойство экземпляра, заданное конструктором, называемым super().constructor.name наследуется экземпляром класса от первого объекта в их цепочке наследования. Цепочка наследования экземпляров Square начинается с Square.prototype и возвращается обратно к Polygon.prototype, ни один из которых не изменяется тестовым кодом.inheritsFrom — это метод класса, определенный в объявлениях классов для Polygon и Rectangle в тестовом коде.Означает ли это: 1. Object.setPrototypeOf(Square, Rectangle); меняет прототип класса Square, а не Square.prototype? 2. После этого изменения экземпляры Square создаются с использованием конструктора Rectangle, что приводит к тому, что свойства задаются конструктором Rectangle? 3. Сам Square.prototype продолжает указывать на Polygon.prototype?
Пожалуйста, используйте Object.getPrototypeOf вместо устаревшего __proto__.
Джимо 1. да, Square.prototype никак не изменяется ни вашим, ни моим кодом. 2. да, 3. да. Я обновил ответ и тестовый код, чтобы лучше это отразить.
Обновление ответа @Bergi в ответ - спасибо.