Вкратце: «Шаблон-прототип — это шаблон, с помощью которого мы можем совместно использовать свойства среди многих объектов одного типа».
Шаблон прототипа — это удобный способ совместного использования свойств многими объектами одного типа. Прототип — это собственный объект JavaScript, к которому объекты могут обращаться через цепочку прототипов.
В наших приложениях нам часто приходится создавать множество объектов одного типа. Полезный способ сделать это — создать несколько экземпляров класса ES6.
Допустим, мы хотим создать много собак! В нашем примере собаки не могут так многого: у них просто есть имя, и они могут лаять!
class Dog { constructor(name) { this.name = name; } bark() { return `Woof!`; } } const dog1 = new Dog("Daisy"); const dog2 = new Dog("Max"); const dog3 = new Dog("Spot");
Обратите внимание, что constructor
содержит свойство name
, а сам класс содержит свойство bark
. При использовании классов ES6 все свойства, определенные в самом классе, в данном случае bark
, автоматически добавляются в prototype
.
Поскольку мы уже знаем, что все дочерние объекты, созданные из класса, наследуют все свойства класса, находящиеся под объектом прототип . После наследования все вновь созданные объекты будут иметь все свойства класса от prototype до свойства __proto__. Подробности см. в моей статье Прототип JavaScript и __proto__ (прототипное наследование) . Вот почему метод bark() будет автоматически добавлен в прототип класса Dog.
Сеть прототипов
Таким образом, значение __proto__
для любого дочернего объекта класса (функция-конструктор) является прямой ссылкой на прототип класса! Всякий раз, когда мы пытаемся получить доступ к свойству объекта, которое не существует непосредственно в объекте, JavaScript проходит по цепочке прототипов, чтобы увидеть если свойство доступно в цепочке прототипов.
Это означает, что если свойство в объекте __proto__ не найдено, JS будет искать это свойство в родительском свойстве prototype.
Вариант использования шаблона прототипа
Шаблон прототипа очень полезен при работе с объектами, которые должны иметь доступ к одним и тем же свойствам. Вместо того, чтобы каждый раз создавать дубликат свойства, мы можем просто добавить свойство в прототип, поскольку все экземпляры имеют доступ к объекту-прототипу.
Поскольку все экземпляры имеют доступ к прототипу, легко добавлять свойства в прототип даже после создания экземпляров. Предположим, вы уже создали 3 объекта A, B и C из класса MyClass. Затем вы чувствуете, что вам нужно создать еще 5 объектов класса MyClass в будущем. Также вы считаете, что все экземпляры (объекты) MyClass должны иметь новое свойство "country". Тогда, если вы просто добавите свойство country в MyClass prototype, это будет очень хорошим и эффективным решением, а также “ страна» будет автоматически унаследована всеми ранее созданными объектами A, B и C. Также все будущие экземпляры будут иметь это свойство country.
Допустим, наши собаки должны уметь не только лаять, но и играть! Мы можем сделать это возможным, добавив свойство play
в прототип.
class Dog { constructor(name) { this.name = name; } bark() { return `Woof!`; } } const dog1 = new Dog("Daisy"); const dog2 = new Dog("Max"); const dog3 = new Dog("Spot"); Dog.prototype.play = () => console.log("Playing now!"); dog1.play();
Термин цепочка прототипов указывает на то, что может быть несколько шагов.
Однако сами прототипы также имеют объект
__proto__
! 👇
Прототипное наследование
Давайте создадим другой тип собаки, суперсобаку! Эта собака должна унаследовать все от обычного Dog
, но она также должна уметь летать. Мы можем создать суперсобаку, расширив класс Dog
и добавив метод fly
.
class SuperDog extends Dog { constructor(name) { super(name); } fly() { return "Flying!"; } }
Давайте создадим летающую собаку по имени Daisy
, пусть она лает и летает!
class Dog { constructor(name) { this.name = name; } bark() { console.log("Woof!"); } } class SuperDog extends Dog { constructor(name) { super(name); } fly() { console.log(`Flying!`); } } const dog1 = new SuperDog("Daisy"); dog1.bark(); dog1.fly();
Выше у нас есть доступ к методу bark
, так как мы расширили класс Dog
. Значение __proto__
на прототипе SuperDog
указывает на объект Dog.prototype
! Это связано с прототипным наследованием. См. ниже (этот ниже Superdog.prototype в основном дает нам имя __proto__ для Superdog) 👇
Смотрите визуально ниже 👇
Становится понятно, почему это называется прототип цепочка: когда мы пытаемся получить доступ к свойству, которое недоступно непосредственно в объекте, JavaScript рекурсивно проходит вниз. все объекты, на которые указывает __proto__
, пока не найдет свойство!
Объект.создать()
Метод Object.create
позволяет нам создать новый объект, которому мы можем явно передать значение его прототипа.
const dog = { bark() { return `Woof!`; }, }; const pet1 = Object.create(dog);
Хотя сам pet1
не имеет никаких свойств, он имеет доступ к свойствам в своей цепочке прототипов! Поскольку мы передали объект dog
в качестве прототипа pet1
, мы можем получить доступ к свойству bark
.
const dog = { bark() { console.log(`Woof!`); } }; const pet1 = Object.create(dog); pet1.bark(); // Woof! console.log("Direct properties on pet1: ", Object.keys(pet1)); console.log("Properties on pet1's prototype: ", Object.keys(pet1.__proto__));
Вывод ниже 👇
Идеальный! Object.create
– это простой способ позволить объектам напрямую наследовать свойства других объектов, указав прототип вновь созданного объекта. Новый объект может получить доступ к новым свойствампутем прохождения по цепочке прототипов.
Преимущества → прототипного наследования
Шаблон прототипа позволяет легко предоставить объектам доступ к свойствам других объектов и наследовать их свойства. Поскольку цепочка прототипов позволяет нам получать доступ к свойствам, которые не определены напрямую в самом объекте, мы можем избежать дублирования методов и свойств, тем самым сокращая объем используемой памяти.
Рекомендация к прочтению
Прочтите другую мою статью о прототипе JavaScript и __proto__: https://medium.com/@anisurrahmanbup/javascript-prototype-proto-prototype-inheritance-5e2d7584140d
Спасибо, что прочитали эту статью. Мне нравится делиться своим 5-летним опытом работы с JavaScript, React, React-native и Node. js с вами каждый день. Пожалуйста, подпишитесь на меня и поделитесь моей статьей с другими, кому она может быть полезна. Ваша поддержка мотивирует меня писать больше, а также обогащает ваши знания.