Вкратце: «Шаблон-прототип — это шаблон, с помощью которого мы можем совместно использовать свойства среди многих объектов одного типа».

Шаблон прототипа — это удобный способ совместного использования свойств многими объектами одного типа. Прототип — это собственный объект 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 с вами каждый день. Пожалуйста, подпишитесь на меня и поделитесь моей статьей с другими, кому она может быть полезна. Ваша поддержка мотивирует меня писать больше, а также обогащает ваши знания.