Вы когда-нибудь видели .prototype, прикрепленный к ответу в сообщении о переполнении стека, с мыслью «отменить!» И немедленным нажатием кнопки возврата? Что ж, тебе больше не о чем беспокоиться. В этой статье исследуется, что такое прототип, что такое прототипное наследование и как оно может принести большую пользу вашему программированию на JavaScript.

Почему важно понимать прототип, прототипное наследование и цепочку прототипов?

Понимание прототипного наследования очень поможет вам сделать ваш код чистым и простым. Что наиболее важно, это поможет вам понять отношения между объектами, то, как эти отношения работают под капотом, и потенциал, который это представляет. Кроме того, эти знания также помогают в работе с устаревшими кодовыми базами, поскольку гораздо чаще .prototype используется в прошлых версиях JavaScript (но это не делает эту концепцию менее важной для понимания).

Что значит наследование?

Проще говоря, вы можете рассматривать наследование как объект, получающий доступ к свойствам и методам другого объекта. Вот и все.

Наследование - это когда объект получает доступ к свойствам и методам другого объекта.

Однако важно отметить, что наследование в JavaScript отличается от наследования во многих других языках программирования (например, C # или Java). В то время как в этих других языках используется так называемое «классическое наследование» (друг / защищенный / частный / интерфейс / и т. Д.), В JavaScript используется «прототипное наследование».

Согласно Википедии, программирование на основе прототипов - это стиль объектно-ориентированного программирования, в котором повторное использование поведения выполняется посредством процесса повторного использования существующих объектов, которые служат прототипами. Эта модель также может быть известна как прототипное, прототипно-ориентированное, бесклассовое или основанное на экземплярах программирование . Звучит немного сложно? Не волнуйтесь, как только вы поймете концепции, лежащие в основе этого, все обретет смысл. Прототипное наследование гибкое, расширяемое и простое для понимания.

Более подробное объяснение можно найти в статье Mozilla о наследовании и цепочке прототипов.

Что такое «Прототип»?

В JavaScript все объекты (включая функции) имеют доступ ко многим встроенным свойствам и методам. Одно из них - свойство prototype.

Свойство прототипа - это просто ссылка на другой объект. Другими словами, когда объект может получить доступ к свойствам и методам другого объекта (с помощью оператора точки и т. д.), этот объект будет его «прототипом. ». Прототипы могут указывать на другие прототипы, а эти прототипы - на другие прототипы, и так далее - это то, что называется цепочкой прототипов.

Что такое цепочка прототипов?

Допустим, вы пытаетесь получить свойство или метод с помощью оператора точки, но свойство или метод недоступны непосредственно для объекта (прототипа), на который ссылается оператор точки. JavaScript проверит прототипы этого прототипа и прототипы этого прототипа и проработает весь путь вниз по цепочке, пока не найдет свойство или метод, к которому вы пытаетесь получить доступ. Если он никогда не найдет его, он выдаст ошибку.

Фактически, даже отдельные объекты могут получить доступ к тому или иному прототипу, если вы этого захотите; давая вам возможность иметь несколько объектов, которые имеют доступ к одному и тому же методу, с одним и тем же местом в памяти.

При попытке доступа к свойству или методу другого объекта, если движок JavaScript не видит это свойство, он будет двигаться вниз по цепочке прототипов, пока не найдет его (или не найдет).

Имеет смысл. Давайте посмотрим на примеры!

Давайте создадим объект person, который имеет два свойства и метод, и еще один объект с такими же свойствами.

Теперь давайте сделаем то, что вы должны никогда не делать, но это хороший пример того, как работает это невидимое свойство «прототип». Давайте установим универсальное свойство __proto__ (не зря оно названо так странно; это делает почти невозможным случайное наименование переменной), которое все современные браузеры присваивают объектам. На самом деле это может вызвать серьезные проблемы с производительностью, так что не делайте этого!

Помните, НИКОГДА этого не делайте!

Теперь, хотя john и person - два совершенно разных объекта, john наследуется от person. Итак, если мы попытаемся получить доступ к свойству на john, которое не существует на john, механизм JavaScript перейдет к person, чтобы найти его.

john уже имеет свойства firstname и lastname, поэтому механизм JavaScript останавливается на этом, когда мы говорим ему найти эти свойства. Не нужно переходить к прототипу, потому что он их уже нашел.

Если john не имеет свойство lastname, тогда, когда мы вызываем john.getFullName(), мы увидим, что "John Default" возвращается, поскольку нет свойства lastname на самом john, но его прототип, person, имеет это свойство со значением Default.

Это свойство __proto__, по сути, невидимо связывает объекты вместе. Как только мы дойдем до самого конца цепочки прототипов, появится база __proto__ (также называемая базовым объектом). Если мы подойдем к концу цепочки прототипов (прямо перед базовым объектом), наше свойство __proto__ будет иметь разные методы в зависимости от типа объекта, к которому оно подключено.

Например, последнее свойство массива __proto__ содержит методы push, pop, reduce и т. Д. Знакомы ли эти методы? Что ж, это просто встроенные методы в конце цепочки прототипов для массива!

Причина, по которой эти методы всегда доступны для вас, заключается в том, что движок JavaScript знает, что ваш массив не имеет свойства push, когда вы вызываете arr.push(). Таким образом, он проходит по цепочке прототипов, находит его и выполняет метод в вашем массиве.

Настройка прототипа вручную

Мы можем использовать .prototype, чтобы «легально» установить прототип объекта без использования объекта __proto__.

Из статьи W3Schools Прототипы объектов JavaScript:

Это то, что вы, вероятно, часто видели в фреймворках, библиотеках, сообщениях о переполнении стека и многом другом. Теперь вы точно знаете, что он делает! Он устанавливает новый метод для прототипа конструктора, чтобы любые объекты, у которых конструктор является прототипом (в данном случае объекты, являющиеся производными этого конструктора функции), будут иметь доступ к методу. Очевидно, что они по-прежнему имеют доступ ко всем свойствам в конструкторе. Хотя эти объекты могут не иметь этого метода напрямую, они все же могут получить к нему доступ по цепочке прототипов.

Вывод

Вот что мы рассмотрели в этой статье:

  • У каждого объекта есть нечто, называемое «прототипом». Прототип - это объект, связанный с объектом, который позволяет ему получать доступ к свойствам и методам другого связанного объекта.
  • Прототипное наследование позволяет объекту получать доступ к методам и свойствам другого объекта с помощью прототипов .
  • Механизм JavaScript использует так называемую цепочку «прототипов» для доступа к свойствам и методам объектов. Если мы пытаемся получить доступ к свойству или методу объекта, который напрямую не имеет свойства или метода, Движок JavaScript будет смотреть на прототип каждого объекта по всей цепочке, пока не найдет его или не найдет.

Как понимание прототипа, прототипного наследования и цепочки прототипов повлияло на ваше программирование? Дайте нам знать об этом в комментариях. Чтобы получить более подробные продвинутые знания JavaScript, ознакомьтесь с остальной частью этой серии!