Что такое prototype в javascript

Встроенные прототипы

Свойство «prototype» широко используется внутри самого языка JavaScript. Все встроенные функции-конструкторы используют его.

Сначала мы рассмотрим детали, а затем используем «prototype» для добавления встроенным объектам новой функциональности.

Object.prototype

Давайте выведем пустой объект:

Вот что происходит:

Когда вызывается new Object() (или создаётся объект с помощью литерала <. >), свойство [[Prototype]] этого объекта устанавливается на Object.prototype по правилам, которые мы обсуждали в предыдущей главе:

Мы можем проверить это так:

Обратите внимание, что по цепочке прототипов выше Object.prototype больше нет свойства [[Prototype]] :

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

Вот более полная картина (для трёх встроенных объектов):

Давайте проверим прототипы:

В браузерных инструментах, таких как консоль разработчика, можно посмотреть цепочку наследования (возможно, потребуется использовать console.dir для встроенных объектов):

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

Примитивы

Самое сложное происходит со строками, числами и булевыми значениями.

Специальные значения null и undefined стоят особняком. У них нет объектов-обёрток, так что методы и свойства им недоступны. Также у них нет соответствующих прототипов.

Изменение встроенных прототипов

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

Так что, в общем, изменение встроенных прототипов считается плохой идеей.

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

Полифил – это термин, который означает эмуляцию метода, который существует в спецификации JavaScript, но ещё не поддерживается текущим движком JavaScript.

Тогда мы можем реализовать его сами и добавить во встроенный прототип.

Заимствование у прототипов

В главе Декораторы и переадресация вызова, call/apply мы говорили о заимствовании методов.

Это когда мы берём метод из одного объекта и копируем его в другой.

Некоторые методы встроенных прототипов часто одалживают.

Например, если мы создаём объект, похожий на массив (псевдомассив), мы можем скопировать некоторые методы из Array в этот объект.

Но это будет невозможно, если obj уже наследует от другого объекта. Помните, мы можем наследовать только от одного объекта одновременно.

Заимствование методов – гибкий способ, позволяющий смешивать функциональность разных объектов по необходимости.

Итого

Задачи

Добавить функциям метод «f.defer(ms)»

Источник

Форум

Discord чат

prototype

Описание, примеры

Как правило, свойство prototype используется для предоставления базового набора функциональных возможностей классу объектов. Новые экземпляры объекта «наследуют» поведение прототипа, присвоенного этому объекту.

В obj.prototype как получить не все экземпляры этого класса, а конкретный экземпляр, используемый юзером сейчас?

this указывает на конкретный экземпляр.

По-моему в код опечатка или ошибка

скобок в этом случае быть не должно, т.к. Array.prototype.max должна быть функцией, а не ее результатом.

Чтобы было понятнее, можно сделать и так:

Ребята, читайте спецификацию, а не такие вот «руководства»:
«. объекты могут создаваться различными способами, в том числе – посредством буквенного обозначения или с помощью конструкторов, которые создают объекты и выполняют код, инициализирующий их полностью или частично путем присвоения их свойствам начальных значений. Каждый конструктор является функцией, которая обладает свойством “prototype”, используемым для реализации прототипного наследования и разделяемых свойств«.
У объекта Javascript (не путать с функцией Object()) нет свойства prototype! Есть неявное свойство, которое ссылается на constructor.prototype. Таким образом, prototype можно задать только для конструктора объекта, но не для самого объекта.

Полностью согласен.
А свойство __proto__ доступно во всех браузерах или нет?
Если сильно надо, то можно им воспользоваться ведь.

Очень дельный комментарий. Тоже обратил внимание на не совсем корректное описание. Спасибо.

Видимо я не до конца понял работу свойства prototype, подскажите пожалуйста где ошибка. Вот мой код:
var ivan = <
im: «Иван»,
>

ivan.prototype.say_name = function(name)
<
this.name = name;
alert(«Привет, меня зовут «+this.name);
>

Скажи пожалуйста, в чем разница

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

Во втором способе такого преимущества нет. Но, поскольку метод getA размещен внутри функции foo (что, вообще говоря, не обязательно), ему доступны объявленные в foo переменные

почему не работает такая конструкция?

Потому что «this» в «in_array» указывает на «fn», а не на «a».

Как часто пишут:
«В отличие от многих языков, this никак не привязано к объекту, а обозначает просто объект, вызвавший функцию.»

В данной ситуации объект ‘a’ имеет свойство fn.
Свойство fn является самостоятельным объектом с методом in_array(el).
Поэтому this указывает именно объект fn.

Источник

Прототипное наследование

В программировании мы часто хотим взять что-то и расширить.

Прототипное наследование — это возможность языка, которая помогает в этом.

[[Prototype]]

Свойство [[Prototype]] является внутренним и скрытым, но есть много способов задать его.

Здесь мы можем сказать, что » animal является прототипом rabbit » или » rabbit прототипно наследует от animal «.

Метод автоматически берётся из прототипа:

Цепочка прототипов может быть длиннее:

Есть только два ограничения:

Операция записи не использует прототип

Прототип используется только для чтения свойств.

Операции записи/удаления работают напрямую с объектом.

В приведённом ниже примере мы присваиваем rabbit собственный метод walk :

Теперь вызов rabbit.walk() находит метод непосредственно в объекте и выполняет его, не используя прототип:

Свойства-аксессоры – исключение, так как запись в него обрабатывается функцией-сеттером. То есть, это, фактически, вызов функции.

По этой причине admin.fullName работает корректно в приведённом ниже коде:

Значение «this»

Неважно, где находится метод: в объекте или его прототипе. При вызове метода this — всегда объект перед точкой.

Это на самом деле очень важная деталь, потому что у нас может быть большой объект со множеством методов, от которого можно наследовать. Затем наследующие объекты могут вызывать его методы, но они будут изменять своё состояние, а не состояние объекта-родителя.

Например, здесь animal представляет собой «хранилище методов», и rabbit использует его.

Источник

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

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

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

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

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

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

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

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

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

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

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

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

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

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

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

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

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

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

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

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

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

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

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

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

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

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

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

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

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

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

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

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

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

Что такое new

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

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

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

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

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

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

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

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

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

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

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

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

P. P. S.

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

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

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

Источник

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

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Более новая информация по этой теме находится на странице https://learn.javascript.ru/prototype-inheritance.

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

Прототип proto

Свойство __proto__ доступно во всех браузерах, кроме IE10-, а в более старых IE оно, конечно же, тоже есть, но напрямую к нему не обратиться, требуются чуть более сложные способы, которые мы рассмотрим позднее.

Пример кода (кроме IE10-):

Иллюстрация происходящего при чтении rabbit.eats (поиск идёт снизу вверх):

Что такое prototype в javascript. Смотреть фото Что такое prototype в javascript. Смотреть картинку Что такое prototype в javascript. Картинка про Что такое prototype в javascript. Фото Что такое prototype в javascript

Обратим внимание – прототип используется исключительно при чтении. Запись значения, например, rabbit.eats = value или удаление delete rabbit.eats – работает напрямую с объектом.

Другими словами, прототип – это «резервное хранилище свойств и методов» объекта, автоматически используемое при поиске.

Метод hasOwnProperty

Обычный цикл for..in не делает различия между свойствами объекта и его прототипа.

Он перебирает всё, например:

Иногда хочется посмотреть, что находится именно в самом объекте, а не в прототипе.

Для того, чтобы перебрать свойства самого объекта, достаточно профильтровать key через hasOwnProperty :

Object.create(null)

Зачастую объекты используют для хранения произвольных значений по ключу, как коллекцию:

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

Чтобы этого избежать, мы можем исключать свойства, не принадлежащие самому объекту:

Однако, есть путь и проще:

Объект, создаваемый при помощи Object.create(null) не имеет прототипа, а значит в нём нет лишних свойств. Для коллекции – как раз то, что надо.

Методы для работы с proto

Чтение: Object.getPrototypeOf(obj) Возвращает obj.__proto__ (кроме IE8-) Запись: Object.setPrototypeOf(obj, proto) Устанавливает obj.__proto__ = proto (кроме IE10-).

Кроме того, есть ещё один вспомогательный метод:

Итого

В современных браузерах есть методы для работы с прототипом:

Также мы рассмотрим, как свойство __proto__ используется внутри самого языка JavaScript и как организовать классы с его помощью.

Источник

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

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