Почему super() вызывает неправильный конструктор при использовании Object.setPrototypeOf?

У меня есть следующий код:

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), похоже, в моем понимании есть пробел.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
2
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чего не хватает, так это того, откуда берется значение super.

  1. Базовый класс (то есть не расширяющий другой класс) создается на Function.prototype. Например

    Object.getPrototype(Polygon) === Function.prototype
    
  2. Класс, расширяющий другой, приводит к двум вещам:

    1. Объект расширенного класса создается на основе расширяемого класса, а не на Function.prototype. Например

        Object.getPrototypeOf(Square) === Polygon
      
    2. Свойство prototype расширенного класса создано на основе свойства prototype расширенного класса. Например

       Object.getPrototypOf(Square.prototype) === Polygon.prototype
      
    3. Обратите внимание, что значение constructor, унаследованное от prototype расширенного класса, не изменяется и остается установленным для объекта расширенного класса. И.Е.

       Square.prototype.constructor === Square 
      

    Это имеет последствия: суперкласс расширенного объекта не может быть определен на основе свойства constructor, унаследованного экземплярами расширенного класса.

    1. Перефразируя пункт 2.1 выше: объект, на котором прототипируется объект расширенного класса, а) изначально является объектом суперкласса и б) эффективно используется ключевым словом 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 и метод класса с именем inheritsFrom
  • значение статического свойства ClassName наследуется 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?

jimo 02.08.2024 15:59

Пожалуйста, используйте Object.getPrototypeOf вместо устаревшего __proto__.

Bergi 02.08.2024 18:03

Джимо 1. да, Square.prototype никак не изменяется ни вашим, ни моим кодом. 2. да, 3. да. Я обновил ответ и тестовый код, чтобы лучше это отразить.

traktor 03.08.2024 06:27

Обновление ответа @Bergi в ответ - спасибо.

traktor 03.08.2024 06:30

Другие вопросы по теме