Всем привет! Меня зовут Сергей, и сегодня я расскажу вам о прототипах. Мы познакомимся с этим механизмом подробнее и узнаем, какую задачу он помогает нам решить. Для начала попробуем сформулировать эту задачу. Пусть у нас есть некоторый объект, который олицетворяет студента. Он записан в литеральной нотации и описывает характеристики студента, а также полезные для него действия. Так, этот объект содержит поле name, которое хранит имя студента (его зовут Billy), и ряд полезных методов, такой как getName, которое возвращает имя нашего студента. Объект студента сложно рассматривать в отрыве от объекта преподавателя. Так же как и у студента, у преподавателя есть ряд полей и методов, например поле name, которое хранит имя преподавателя. Нашего преподавателя зовут Sergey. Если мы посмотрим на два этих объекта внимательнее, мы увидим, что в них очень много похожего. Так, у каждого из них есть метод getName, который выполняет одинаковую работу: он просто возвращает имя объекта. Таким образом, мы дублируем реализацию одного и того же метода в двух разных объектах. А дублирование кода — это яркий признак того, что этот код впоследствии будет достаточно сложно поддерживать. И это проблема. К счастью, решение очень простое. Мы можем выделить общий код, общие части в отдельную конструкцию. Итак, выделим общие поля и методы объектов студента и преподавателя в отдельный объект. Личность, или person, будет хорошим названием, объединяющим для двух этих объектов — студента и преподавателя, ведь каждый из них, бесспорно, личность. Таким образом мы получим три несвязанных объекта: студента, преподавателя и личность. Так как мы забрали у наших объектов студента и преподавателя полезный метод getName, нам необходимо после нашего рефакторинга решить следующую задачу: а именно научить студента пользоваться общим кодом, который мы вынесли в другой объект — в объект person. Для решения этой задачи мы можем воспользоваться уже знакомым вам методом — методом заимствования. Для этого мы можем позаимствовать метод getName у объекта person и вызвать его при помощи метода call, передав первым аргументом объект студента. Таким образом, внутри метода при его выполнении this будет ссылаться на объект студента, и мы получим желаемый результат. Но выглядит такая конструкция достаточно громоздко и неестественно, а нам хотелось бы вызывать метод getName, как и раньше, от лица студента, как это было до рефакторинга. Можем ли мы связать два наших объекта студента и личность (person) таким образом, чтобы это было возможным? К счастью, в языке предусмотрен механизм для создания такой связи. Необходимо лишь в специальное внутреннее поле [[Prototype]] одного объекта записать ссылку на другой. Так, мы можем записать в это поле у объекта student ссылку на объект person и получить желаемое поведение. К сожалению, обратиться напрямую ко внутреннему полю, конечно, нельзя. Но существует ряд способов, которые позволяют записать в него новое значение. Один из них — специальный set/get_proto_ Выглядит он немножечко странно, но делает ровно то, что нам нужно. На этом этапе мы можем дать определение прототипу. Итак, объект, на который указывает ссылка во внутреннем поле [[Prototype]], и называется прототипом. В реальной жизни мы прототипами обычно называем некоторые базовые конструкции, на основе которых создаются уже более детальные и законченные. Так и здесь можно сказать, что объект person (личность) послужил прототипом для объекта студента. Таким образом, мы решили нашу задачу, устранили при помощи механизма прототипов дублирование кода, но при этом сохранили удобный способ вызова методов у исходных объектов.