Прототип Javascript: первый подробный взгляд на объекты
Прототип — это атрибут, который содержится в каждом объекте в javascript (если объект не создан с использованием Object.create(null)
), однако его внутренняя работа известна очень немногим. Понимание того, как назначается атрибут прототипа, является важной концепцией, с помощью которой можно применять наследование в javascript. Прежде чем понять прототип, вы должны знать некоторые основные принципы и использование объектов. Если вы не знакомы с объектами, пожалуйста, прочитайте мою статью Основы объектов javascript. В этой статье мы подробно рассмотрим, как назначаются прототипы при создании объектов и почему это важно.
"источник"
Что такое свойство прототипа и что оно содержит?
Каждая функция-конструктор JavaScript, созданная любым доступным методом, содержит свойство. Это свойство prototype. Важно отметить, что свойство прототипа само по себе является объектом.
- Свойство прототипа функции-конструктора можно использовать для доступа/изменения методов и других свойств, присутствующих в объекте-прототипе, который был назначен во время его создания.
- У каждого объекта-прототипа есть свойство, называемое конструктором. Это свойство указывает на саму Функцию-конструктор.
Давайте посмотрим на пример, чтобы понять это лучше:
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
, мы получим следующий результат.
Вот как все работало до сих пор:
- name — это функция-конструктор. Он содержит свойство prototype.
- Это свойство прототипа имеет атрибут, называемый конструктор, который указывает на саму функцию-конструктор Имя. К этому свойству можно добавить любые дополнительные атрибуты.
- Когда новый объект
jensen
был создан с помощью конструктора Name, этот объект получил доступ ко всем свойствам, принадлежащим функции Name, включая ее прототип. - Доступ к прототипу функции-конструктора
Name
можно получить из нового объектаjensen
с помощью объекта__proto__
. - Поскольку 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
, то увидим следующее:
- Объект apple1 содержит два основных свойства —
name
иcolor
. Эти свойства имеют то же значение, которое было присвоено им при его создании. - Свойство
__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.