что такое прототип объекта

Прототипы в JavaScript

Дата: 24.03.2019 Категория: JavaScript Комментарии: 0

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

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

Как видно из приведенного выше примера, свойство age добавлено к экземпляру studObj1. Однако экземпляр studObj2 не будет иметь свойства age, поскольку он определен только для экземпляра studObj1.

Так что же делать, если мы хотим добавить новые свойства на более позднем этапе к функции, которая будет использоваться всеми экземплярами?

Что такое прототип

Каждая функция включает объект-прототип по умолчанию.

Итак, используйте свойство prototype функции в вышеприведенном примере, чтобы добавить свойство age для всех объектов, как показано ниже.

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

Вы можете отлаживать и видеть свойство prototype объекта или функции в инструменте разработчика Chrome или Firefox. Рассмотрим следующий пример.

Прототип объекта

Как упоминалось ранее, свойство прототипа объекта невидимо. Используйте метод Object.getPrototypeOf(obj) вместо __proto__ для доступа к объекту-прототипу.

Объект прототипа включает в себя следующие свойства и методы.

constructorВозвращает функцию, которая создала экземпляр.
__proto__Это невидимое свойство объекта. Он возвращает объект-прототип функции, на которую он ссылается.
hasOwnProperty()Возвращает логическое значение, указывающее, содержит ли объект указанное свойство как прямое свойство этого объекта и не унаследованое через цепочку прототипов.
isPrototypeOf()Возвращает логическое указание, находится ли указанный объект в цепочке прототипов объекта, для которого вызывается этот метод.
propertyIsEnumerable()Возвращает логическое значение, которое указывает, является ли указанное свойство enumerable или нет.
toLocaleString()Возвращает строку в локальном формате.
toString()Возвращает строку.
valueOfВозвращает примитивное значение указанного объекта.

Chrome и Firefox обозначают прототип объекта как __proto__, который является публичной ссылкой, тогда как внутри он ссылается как [[Prototype]]. Internet Explorer ниже версии 11 не включает __proto__.
Метод getPrototypeOf() стандартизирован начиная с ECMAScript 5 и доступен начиная с IE 9.

Изменение прототипа

Как упоминалось выше, каждый прототип объекта связан с объектом-прототипом функции. Если вы измените прототип функции, то только новый объект будет связан с измененным прототипом. Все остальные существующие объекты по-прежнему будут ссылаться на старый прототип функции. Следующий пример демонстрирует этот сценарий.

Использование прототипов

Прототип объекта используется движком JavaScript в двух случаях:
для поиска свойств и методов объекта;
для реализации наследования в JavaScript.

В приведенном выше примере метод toString() не определен в Student, тогда как и где он находит toString()?

Источник

Прототипы это объекты (и почему это важно)

JavaScript – один из главных языков нашего стека в Хекслете. Мы используем ReactJS и NodeJS в интерактивных частях платформы, и сделали вводный курс (более продвинутые – на подходе). Любовь к JS помогла опубликовать этот перевод хорошего эссе «Prototypes are Objects (and why that matters)».

Этот пост рассчитан на тех, кто знаком с объектами в JavaScript и знает, как прототип определяет поведение объекта, что такое функция-конструктор и как свойство .property конструктора относится к объекту, который он конструирует. Общее понимание синтаксиса ECMAScript 2015 тоже не помешает.

Мы всегда могли создать класс в JavaScript таким образом:

Person это функция-конструктор, а также класс в JavaScript’овом понимании этого слова. ECMAScript 2015 дает возможность использовать ключевое слово class и т.н. “compact method notation”. Это синтаксический сахар для написания функций и присвоения методов его прототипу (там все чуть сложнее, но сейчас это не важно). Так что мы можем написать класс Person вот так:

Клево. Но под капотом все равно есть функция-конструктор с привязкой к имени Person, и есть объект Person.prototype, который выглядит так:

Прототипы это объекы

Если нужно изменить поведение объекта в JavaScript, можно добавить, удалить или изменить методы объекта через добавление, удаление или изменение функций, привязанных к свойствам этого объекта. В этом отличие от многих “классических” языков, в которых есть специальная форма (например, в Руби есть def) для задания методов.

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

Именно это и делает ECMAScript 5 код выше, и синтаксис class “рассахаривает” его в эквивалентный код.

Прототипы это “всего лишь объекты”, и это означает, что мы можем использовать любые техники, которые работают на объектах. Например, вместо привязки одной функции к прототипу, мы можем совершать массовую привязку с помощью Object.assign:

И, конечно, мы можем использовать компактный синтаксис если захотим:

Mixins (примеси)

Так как class “рассахаривает” код в конструктор-функции и прототипы, мы можем использовать примеси вот так:

Мы только что “вмешали” методы по сбору книг в класс Person. Круто, что можно вот так просто писать код, но можно и давать названия:

Так можно продолжать сколько захочется:

Зачем использовать примеси

Сборка классов с помощью базовой функциональности (Person) и миксинов (BookCollector и Author) дает некоторые преимущества. Во-первых, иногда функциональность невозможно хорошо разложить на части в красивой древовидной структуре. Авторы книг могут быть корпорациями, а не людьми. И антикварные книжные лавки собирают книги так же, как книголюбы.

Такие примеси, как BookCollector или Author могут быть вмешаны в несколько разных классов. Попытки композиции функциональности с помощью наследования не всегда удачны.

Еще одно преимущество не так очевидно в простом примере, но в продакшн-системах классы могут разрастаться до нелепых размеров. Даже если примесь не используется в нескольких классах, декомпозиция большого класса с помощью примесей помогает удовлетворить принцип принцип единственной обязанности. Каждый миксин может иметь тольк одну область ответственности. Все это упрощает понимание и тестирование.
почему это важно

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

Например, в Руби использоват миксины легко, потому что с самого начала там есть специальная фича – модули. В других ОО-языках использовать миксины сложно, потому что система классов не поддерживает их, и они не очень вяжутся с мета-программированием.

Источник

Прототипы в JS и малоизвестные факты

Лирическое вступление

Получив в очередной раз кучу вопросов про прототипы на очередном собеседовании, я понял, что слегка подзабыл тонкости работы прототипов, и решил освежить знания. Я наткнулся на кучу статей, которые были написаны либо по наитию автора, как он «чувствует» прототипы, либо статья была про отдельную часть темы и не давала полной картины происходящего.

Оказалось, что есть много неочевидных вещей из старых времён ES5 и даже ES6, о которых я не слышал. А еще оказалось, что вывод консоли браузера может не соответствовать действительности.

Что такое прототип

Объект в JS имеет собственные и унаследованные свойства, например, в этом коде:

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

Как выглядит прототип

Да кто такой этот ваш constructor

constructor – это ссылка на функцию, с помощью которой был создан объект:

Не совсем понятна идея зачем он был нужен, возможно, как способ клонирования объекта:

Но я не нашел подходящий пример его использования, если у Вас есть примеры проектов, где это использовалось, то напишите об этом. В остальном же использовать constructor лучше не стоит, так как это writable свойство, которое можно случайно перезаписать, работая с прототипом, и сломать часть логики.

Где живёт прототип

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

О чем вам недоговаривает дебаггер, или он вам не прототип

Свойство __proto__ является геттером и сеттером для внутреннего слота [[Prototype]] и находится в Object.prototype :

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

Из-за этого я избегал записи __proto__ для обозначения прототипа. __proto__ находится не в самом объекте, что приводит к неожиданным результатам. Для демонстрации попробуем через __proto__ удалить прототип объекта и затем восстановить его:

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

В консоли Chrome foo будет выглядеть следующим образом:

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

А теперь уберем связь между baz и Object.prototype :

И теперь в консоли Chrome видим следующий результат:

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

Как работать с прототипом объекта

Рассмотрим основные способы работы с прототипом: изменение прототипа и создание нового объекта с указанным прототипом.

А теперь менее категоричный вопрос создания нового объекта с прототипом. Для этого есть следующие способы.
Стандартный способ:

И в случае если отсутствует поддержка всего вышеперечисленного:

Функции и конструкторы

А теперь поговорим про функции и как они работают в качестве конструкторов.

Функция Person тут является конструктором и создает два поля в новом объекте, а цепочка прототипов выглядит так:

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

И теперь вызов user.fullName() вернет строку «John Doe».

Что такое new

На самом деле оператор new не таит в себе никакой магии. При вызове new выполняет несколько действий:

Все эти действия можно сделать силами самого языка, поэтому можно написать свой собственный оператор new в виде функции:

Но начиная с ES6 волшебство пришло и к new в виде свойства new.target, которое позволяет определить, была ли вызвана функция как конструктор с new, или как обычная функция:

new.target будет undefined для обычного вызова функции, и ссылкой на саму функцию в случае вызова через new ;

Наследование

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

Фиолетовым цветом обозначены поля объекта (они все находятся в самом объекте, т.к. this у всей цепочки прототипов один), а методы желтым (находятся в прототипах соответствующих функций)
Вариант 1 предпочтительнее, т.к. Object.setPrototypeOf может привести к проблемам с производительностью.

Сколько вам сахара к классу

Для того чтобы облегчить классическую схему наследование и предоставить более привычный синтаксис, были представлены классы, просто сравним код с примерами Person и Student:

Уменьшился не только бойлерплейт, но и поддерживаемость:

При этом цепочка прототипов получается идентичной примеру с явным указанием prototype у функций конструкторов.

Наивно было бы ожидать, что одна статья ответит на все вопросы. Если у Вас есть интересные вопросы, экскурсы в историю, аргументированные или беспочвенные заявления о том, что я сделал все не так, либо правки по ошибкам, пишите в комментарии.

P. P. S.

К сожалению главный кликбейт статьи перестал быть актуальным. В данный момент Chrome (версия 93, на момент обновления статьи) перестал использовать __proto__ для обозначения прототипа, и теперь отображает его как слот [[Prototype]] :

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

Справедливости ради хочу отметить что в Firefox (92) также не используется обозначение __proto__ :

Источник

Прототипы объектов

Базовая компьютерная грамотность, базовое понимание HTML и CSS, знакомство с основами JavaScript (см. Первые шаги и Строительные блоки) и основы OOJS (см. Введение в объекты).

Понять прототипы объектов JavaScript, как работают прототипные цепочки и как добавить новые методы в prototype свойство.

Язык основанный на прототипах?

JavaScript часто описывают как язык прототипного наследования — каждый объект, имеет объект-прототип, который выступает как шаблон, от которого объект наследует методы и свойства. Объект-прототип так же может иметь свой прототип и наследовать его свойства и методы и так далее. Это часто называется цепочкой прототипов и объясняет почему одним объектам доступны свойства и методы которые определены в других объектах.

Точнее, свойства и методы определяются в свойстве prototype функции-конструктора объектов, а не в самих объектах.

Давайте посмотрим на пример, чтобы стало понятнее.

Понимание прототипа объектов

В этом примере мы определили конструктору функцию, например:

Затем мы создаём экземпляр объекта следующим образом:

Если вы наберёте « person1. » в вашей консоли JavaScript, вы должны увидеть, что браузер пытается автоматически заполнить это с именами участников, доступных на этом объекте:

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

Свойство prototype: Где определены унаследованные экземпляры

Снова create()

Ранее мы показали, как метод Object.create() может использоваться для создания нового экземпляра объекта.

Свойство constructor

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

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

Например, попробуйте это:

Изменение прототипов

Давайте рассмотрим пример изменения свойства prototype функции-конструктора — методы, добавленные в прототип, затем доступны для всех экземпляров объектов, созданных из конструктора.

Должно появиться всплывающее окно, с именем пользователя, определённым в конструкторе. Это действительно полезно, но ещё более полезно то, что вся цепочка наследования обновляется динамически, автоматически делая этот новый метод доступным для всех экземпляров объектов, полученных из конструктора.

Подумайте об этом на мгновение. В нашем коде мы определяем конструктор, затем мы создаём экземпляр объекта из конструктора, затем добавляем новый метод к прототипу конструктора:

Примечание: Если у вас возникли проблемы с получением этого примера для работы, посмотрите на наш пример oojs-class-prototype.html (см. также это running live).

Это не очень гибко, так как человека нельзя назвать так. Было бы намного лучше сделать это, создав fullName из name.first и name.last :

Этот образец можно увидеть в действии в примере приложения плана школы Петра Залевы.

Резюме

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

В следующей статье мы рассмотрим то, как вы можете реализовать наследование функциональности между двумя собственными настраиваемыми объектами.

Источник

JavaScript парадигма объектов и прототипов. Простое объяснение.

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

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

Что такое объекты?

Объекты на самом базовом уровне можно представить как список пар ключ / значение, причем ключ всегда является строкой, …а значение…. может быть чем-то иным. Это похоже на то, что вы можете назвать «картой» или «словарем» на других языках. Все, базовые сущности которые вы обычно создаете в JavaScript, и которое не является примитивами, является объектами. Объекты облегчают упаковку и перемещение данных, а создание новых объектов в JavaScript более тривиально, чем в других объектно-ориентированных, таких как Java / C #.

Когда говорят об объектах часто упоминают термин “свойство”. Этот термин означает определенную пару ключ/значение. Чтобы дать вам представление о том, как выглядят объекты, мы начнем с простого примера объекта с двумя свойствами: age и weight.

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

Функции являются объектами

Как было замечено раньше, в Javascript все что не примитивы являются объектами, включая функции… Я знаю это может показаться странным. Сложно думать о функции как о группе пар ключ/значение. Так как функции объекты, их часто еще называют как объекты-фукнции. Это специальные группа пар ключ/значение с особыми свойствами для выполнения кода и передачи значений. Мы рассмотрим эти свойства в следующем разделе. В начале давайте поговорим почему функции так важны.

Можно сказать, что объекты-функции имеют две основные цели. Если мы хотим создать блок логики, который выполняется, мы можем использовать объект-функцию: точно так же, как «методы» в любом другом языке программирования. Другой целью является то, что если мы захотим создать объекты со значениями и методами, и возможно, с некоторой логикой для установки этих значений, мы также будем использовать объекты-функции. Здесь вы можете думать о объектах-функциях как о «классах», которые ведут себя как объектно-ориентированные языки (то есть Java / C #).

В стандартном случае функции в JavaScript выглядят как функции на любом другом языке; они выполняют логику для выполнения конкретной задачи.

Если мы хотим упаковать небольшую группу данных, как, например, два наших свойства в объекте Dog, то достаточно простой список пар ключ / значение. Но что если мы захотим создать несколько объектов Dog? Может быть, некоторые значения должны быть статическими, а другие динамическими. В данном случае нам понадобятся объекты-функции. Когда мы вызываем функцию с помощью new, объект (он же экземпляр-объект) вернется со свойствами установленными с помощью ключевого слова this внутри функции.

Объекты против Прототипов

Теперь давайте поговорим о прототипах. Вы часто слышали, что JavaScript — это язык на основе прототипов. Значит ли это, что объекты и прототипы — это одно и то же? Ну, не совсем. Прототипы являются особым типом объекта и существуют как свойство для объектов-функций. Когда мы пытаемся получить доступ к ключу объекта-функции, JavaScript проверяет его свойство prototype, чтобы увидеть, есть ли оно там. Если нет, он пойдет вверх по цепочке прототипов, чтобы попытаться найти его. Чтобы понять цепочку прототипов, нам нужно узнать о функциях и наследовании.

Функции и наследование

Всякий раз, когда экземпляр объекта возвращается из вызова функции с использованием new, ему присваивается свойство с ключом __proto__. Значение этого свойства является свойство prototype функции, которая его создала.

Если мы попытаемся получить доступ к свойству объекта-экземпляра, а его там нет, JavaScript сначала перейдет к __proto__ и проверит, находится ли оно в прототипе родительской функции. Чтобы увидеть это в действии, давайте установим свойство в одном из атрибутов prototype нашего объекта Dog, и когда мы вызовем Spot[‘whatever the key name is’] или Bingo[‘whatever the key name is’], мы получим то же значение. Это будет работать даже после того, как будут созданы оба объекта-экземпляра dog.

Создание методов таким способом (в отличие от использования this внутри функций) особенно полезна, потому что создание метода будет происходить только один раз, а не каждый раз, когда вызывается new. Это будет экономить память и увеличит производительность.

Рассмотрим наследование немного глубже

Давайте рассмотрим несколько примеров JavaScript, движущихся вверх по цепочке прототипов для доступа к hasOwnProperty у некоторых объектов.

Литеральный объект (Object-literal):

Объект Экземпляр (Instance-Object):

Объект Функция (Function-object):

А как насчет __proto__ у объектов-функций?

Как уже говорилось, __proto__ помогает связать объекты с прототипами, от которых они наследуются. А как насчет вызова __proto__ непосредственно для объектов-функций? JavaScript действительно имеет встроенный объект-функцию под названием Function. Свойство __proto__ каждой функции указывает на Function.prototype, который является функцией, но не имеет свойства prototype и возвращает неопределенное значение. Function.prototype определяет поведение по умолчанию, от которого наследуются все функции. Как и все свойства прототипов функциональных объектов, он по-прежнему имеет __proto__, который указывает на Object.prototype.

Выше сказанное можно продемонстрировать следующей картинкой. Обратите внимание, что Object.prototype — это то, откуда все происходит.

что такое прототип объекта. Смотреть фото что такое прототип объекта. Смотреть картинку что такое прототип объекта. Картинка про что такое прототип объекта. Фото что такое прототип объекта

Многоуровневое наследование

Когда мы говорим о наследовании, мы обычно думаем об объектах экземпляра, возвращаемых из функций. С прототипом вы также можете создать несколько уровней наследования и иметь объекты-функции, наследуемые от других объектов-функций. Все, что вам нужно сделать, это установить прототип дочернего объекта-функции в другой экземпляр прототипа родительского объекта-функции. Тогда все свойства родителя будут скопированы. Если родительская функция получает аргументы, такие как age и weight у Dog, используйте .call, чтобы установить свойство this дочернего объекта.

Labrador наследуется от Dog:

Классы

Классы в JavaScript, созданные в ES6, являются просто синтаксическим сахаром над объектами-функциями. Вместо того, чтобы набирать прототип снова и снова, чтобы определить методы для функций, с ключевым словом class мы можем просто определить группу методов внутри класса. С помощью ключевого слова extends классы могут наследоваться от других классов без необходимости использовать Object.create и Object.call. Лично мне больше нравится использовать классы, но имейте в виду, что старые браузеры могут их не поддерживать. Для решения этой проблемы есть такие инструменты, как Babel.

Использование объектов функций:

Аналогичный код но с использованием классов:

Объекты против примитивов

Код JavaScript по сути сводится к двум основным типам: примитивам и объектам. В JavaScript есть 5 примитивов: boolean, number, string, null и undefined. Примитивы — это всего лишь простые значения без свойств. Три примитива: boolean, number и string имеют дубликаты объектов, которые JavaScript использует как оболочку во время определенных операций. Например, «some string».length вызовет new String() и вернет объект-экземпляр, обернутый вокруг строкового примитива, чтобы можно было получить доступ к свойству length. Как уже упоминалось, все объекты-экземпляры наследуются от Object. Так что со строкой вы можете использовать методы родительского объекта, например тот же hasOwnProperty.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *