Привет, ребята, за последние пару месяцев я взял интервью у нескольких парней. Большинство из них знакомы с такими понятиями, как замыкания, промисы и т. д., но когда я спрашиваю их о наследовании, они всегда упоминают ключевое слово extends
, но лишь немногие упоминают (или, по крайней мере, знают) цепочку prototype
.
Расширяет новый прототип
Совершенно неправильно! extends
— это просто синтаксический сахар для prototype
за кулисами JS указывает родительскому классу на constructor
prototype
.
Чтобы понять это, давайте возьмем следующий вопрос интервью (один из моих любимых, должен сказать):
Используя наследование, передайте функцию
multiply
новомуArray
. Эта функция должна изменять текущий массив, добавляя те же значения, но умножая их на себя:
const a = [1,2, 3,4,5] a.multiply() console.log(1) // [1,2,3,4,5,1,4,9,16,25]
Для опытных разработчиков ответ действительно прост, нам просто нужно использовать цепочку prototype
. Но для сумасшедших/гениальных разработчиков prototype
— не единственный ответ, поскольку мы можем создавать массивы с помощью ключевого слова new
, тогда мы также можем использовать extends
!
Как видите, помимо другого синтаксиса, есть одно большое отличие: при использовании prototype
все массивы, даже созданные с использованием ключевого слова new
, имеют доступ к функции multiply
. Но почему? хорошо давайте посмотрим на объект
Array
является итерируемым объектом по определению, и по определению все объекты имеютprototype
Прототип против наследования классов
Если мы используем Prototype Inheritance, наша функция multiply
присоединяется непосредственно к Array
prototype
, поэтому по определению все экземпляры или вызовы будут иметь к ней доступ благодаря цепочке prototype
. Вот почему переменные b
и c
имеют доступ к этой функции. Таким образом, мы могли бы сказать, что функция конструктора указывает itsprototype
на свой родительский объект (конечно, мы можем изменить это, но по умолчанию constructor.prototype
указывает на свой родительский объект).
Теперь, если мы используем наследование классов, мы видим, что отношения сильнее, почему? ну, constructor
prototype
, а также прямое prototype
из FancyArray
имеет функцию multiply
, и оба указывают на объект Array
, это то, что называют таксономиями классов (простыми словами: классификация классов). Итак, FancyArray
— это класс типа Array
.
Несмотря на то, что FancyArray
таксономия Array
, это не означает, что Array
имеет доступ к функции multiply
:
FancyArray
напрямую зависит от Array
, но Array
не знает о кастомных модификациях, которые есть у FancyArray
, так что давайте вспомним немного теории:
Наследование классов берет план в качестве основы для создания нового. Дочерний план будет иметь то же поведение, функции и ошибки, что и родительский, но родительский план ничего не будет знать о своих дочерних элементах.
Вывод
В JS нет типичного наследования классов, JS создает прочную связь между родителем и дочерним элементом, указывая свои prototype
и constructor.prototype
на родителя prototype
. Это работает, но мы теряем прямой контроль над ребенком. По моему личному мнению, наследование классов отлично работает для таких сценариев, как React, где мы создаем Components
с точно таким же поведением, как у React, конечно, мы можем добавить некоторые настройки, но эта настройка не должна распространяться на другие Components
Прототипное наследование — это косвенная связь между объектами, поскольку мы используем prototype
для передачи пользовательских переменных/функций. Почему непрямой? ну, prototype
представляет родительский объект, это просто ссылка от дочернего к родительскому, это означает, что он не является частью самого объекта. Чтобы доказать эту мысль, мы можем использовать функцию hasOwnProperty
. Как вы, возможно, знаете, эта функция будет проверять только прямые атрибуты объекта, поэтому она игнорирует все в prototype
, так как это просто представление родителя.
Время шуток…
Спасибо, что прочитали этот пост, и в качестве награды у нас есть мультфильм Дилберта!