Прототип Javascript: первый подробный взгляд на объекты

Прототип — это атрибут, который содержится в каждом объекте в javascript (если объект не создан с использованием Object.create(null)), однако его внутренняя работа известна очень немногим. Понимание того, как назначается атрибут прототипа, является важной концепцией, с помощью которой можно применять наследование в javascript. Прежде чем понять прототип, вы должны знать некоторые основные принципы и использование объектов. Если вы не знакомы с объектами, пожалуйста, прочитайте мою статью Основы объектов javascript. В этой статье мы подробно рассмотрим, как назначаются прототипы при создании объектов и почему это важно.

"источник"

Что такое свойство прототипа и что оно содержит?

Каждая функция-конструктор JavaScript, созданная любым доступным методом, содержит свойство. Это свойство prototype. Важно отметить, что свойство прототипа само по себе является объектом.

  1. Свойство прототипа функции-конструктора можно использовать для доступа/изменения методов и других свойств, присутствующих в объекте-прототипе, который был назначен во время его создания.
  2. У каждого объекта-прототипа есть свойство, называемое конструктором. Это свойство указывает на саму Функцию-конструктор.

Давайте посмотрим на пример, чтобы понять это лучше:

function Name(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.fullName = firstName + " " + lastName
}

var jensen = new Name("Jensen", "Ackles");
console.log(jensen);

Если я попытаюсь получить доступ к этому console.log, содержащему все свойства объекта jensen, мы получим следующий результат.

Вот как все работало до сих пор:

  1. name — это функция-конструктор. Он содержит свойство prototype.
  2. Это свойство прототипа имеет атрибут, называемый конструктор, который указывает на саму функцию-конструктор Имя. К этому свойству можно добавить любые дополнительные атрибуты.
  3. Когда новый объект jensen был создан с помощью конструктора Name, этот объект получил доступ ко всем свойствам, принадлежащим функции Name, включая ее прототип.
  4. Доступ к прототипу функции-конструктора Name можно получить из нового объекта jensen с помощью объекта __proto__.
  5. Поскольку prototype сам по себе является объектом, он также содержит атрибут prototype. Так создается цепочка прототипов.

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

Другая альтернатива __proto__ включает Object.getPrototypeOf() или objectInstance.constructor.prototype. Если вы рассмотрите приведенный выше пример, его можно использовать следующими способами для доступа к одному и тому же свойству прототипа:

Object.getPrototypeOf(jensen);
jensen.constructor.prototype;

Сеть прототипов

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

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

function Fruit() {
    this.value = 10;
    this.quantity = 35;
}

function Apple(name, color) {
    this.name = name;
    this.color = color
}

Apple.prototype = new Fruit();

var apple1 = new Apple("Apple", "Red");
console.log(apple1);

Если мы проверим внутренние свойства объекта apple1, то увидим следующее:

  1. Объект apple1 содержит два основных свойства — name и color. Эти свойства имеют то же значение, которое было присвоено им при его создании.
  2. Свойство __proto__ объекта apple1 указывает на экземпляр объекта Fruit. Это, в свою очередь, содержит еще два свойства value и quantity.

3. Если мы проверим свойство __proto__ экземпляра Fruit, то увидим, что оно в конечном счете указывает на прототип объекта javascript.

4. Когда свойство не присутствует непосредственно в объекте, javascript перемещается вверх по цепочке прототипов, чтобы найти свойство в его непосредственном прототипе. Подобно цепочке области действия в javascript, цепочка прототипов также идет вверх по лестнице, пока не будет достигнут Object.prototype.

Использование прототипа: наследование и встроенные методы

Прототип широко используется в javascript для реализации наследования. Традиционно javascript использовался только для написания сценариев, и он не требовал предоставления функций объектно-ориентированного программирования, как другие языки. Однако концепция прототипа может использоваться для наследования методов и свойств от одной функции-конструктора к другой.

Рассмотрим следующий пример:

function Fruit() {
    this.value = 10;
    this.quantity = 35;
}

Fruit.prototype.setValue = function(value) {
    this.value = value;
}

function Apple(name, color) {
    this.name = name;
    this.color = color
}

Apple.prototype = new Fruit();

var apple1 = new Apple("Apple", "Red");
apple1.setValue(20);

console.log(apple1.name); // Apple
console.log(apple1.value); // 20
console.log(apple1.quantity); // 35

В приведенном выше примере, несмотря на то, что новый объект apple1 не имеет свойств value и quantity, мы все еще можем получить к ним доступ. Следует отметить, что метод setValue, добавленный к свойству прототипа конструктора фруктов, также доступен через объект apple1. Вот как наследование реализовано в javascript.

Когда объекты создаются с помощью любого конструктора, он содержит определенные встроенные методы, которые можно применять к объекту. hasOwnProperty (), isPrototypeOf (), propertyIsEnumerable (), toLocaleString (), toString () и valueOf (). — это некоторые из встроенных методов, доступных для всех объектов. Это связано с тем, что все объекты в JavaScript наследуют свойства и методы от Object.prototype.

Все встроенные конструкторы, такие как Array(), Number(), String(), etc, создаются из конструктора javascript Object, и их прототип также назначается Object.prototype.

Проблемы с прототипами

Прототипы в javascript имеют множество применений, они используются для наследования методов родительских функций, их также можно использовать для абстрагирования уровня данных и предоставления только методов получения и установки для управления значениями, принадлежащими различным объектам. Однако у прототипов есть свои недостатки. Все свойства, добавленные к объекту-прототипу, общие для каждого экземпляра объекта, созданного с использованием его Функции-конструктора. Любое изменение одного из свойств будет отражаться на всех объектах.

Рассмотрим следующий пример:

function Apple(name, color) {
    this.name = name;
    this.color = color
}

Apple.prototype.value = 20;

var apple1 = new Apple("Apple", "Red");
var apple2 = new Apple("Apple2", "Wheatish Red");

console.log(apple1.name); // Apple
console.log(apple1.value); // 20
console.log(apple2.value); // 20

Apple.prototype.value = 40;
console.log(apple1.value); // 40
console.log(apple2.value); // 40

apple1.value = 30;
console.log(apple1.value); // 30
console.log(apple2.value); // 40

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

Чтобы смягчить эту проблему, можно реализовать комбинацию шаблонов Конструктор — Прототип. Значения данных, принадлежащие объекту, можно сохранить конфиденциальными и уникальными с помощью функции-конструктора. Общие методы, которые могут использоваться всеми объектами для управления данными, могут быть добавлены в объект Prototype.

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

Первоначально опубликовано на https://aparnajoshi.netlify.app.