JavaScript, как говорят, является прототипом. Итак, «прототипы» должны быть важной концепцией, верно?
Сегодня я собираюсь объяснить, что такое прототипы, что вам нужно знать, и как эффективно использовать прототипы.
Что такое прототипы?
Прежде всего, Не позволяйте слову «прототип» ввести вас в заблуждение . «Прототип» в JavaScript – это не то же самое, что «прототип» на английском языке. Это не означает начальную версию продукта, которая была быстро собрана вместе.
Вместо этого прототип в JavaScript – это просто слово, которое абсолютно ничего не значит. Мы можем заменить прототип апельсинами, и это может означать одно и то же.
Например, подумайте об Apple. До того, как компьютеры Apple стали популярными, вы, вероятно, подумаете о Apple как о фруктах красного цвета. ” Apple “в Apple Computers не имеет значения изначально – но сейчас это делает.
В случае JavaScript прототип относится к системе. Эта система позволяет вам определять свойства на объектах, которые можно получить через экземпляры объекта.
::: Примечание прототип тесно связан с объектно -ориентированным программированием. Это не имеет смысла, если бы вы не понимали, о чем предназначено программирование, ориентированное на объект.
Я предлагаю вам ознакомиться с Эта вступительная серия о объектно -ориентированном программировании Прежде чем идти дальше. :::
Например, Массив это план для массивов. Вы создаете экземпляр массива с [] или New Array () Анкет
const array = ['one', 'two', 'three']
console.log(array)
// Same result as above
const array = new Array('one', 'two', 'three')
Если вы Консоль.log В этом массиве вы не видите никаких методов. Но все же вы можете использовать такие методы, как конг , Среза , фильтр и карта !
Почему?
Потому что эти методы расположены в прототипе массива. Вы можете расширить __proto__ объект (Chrome Devtools) или <Прототип> Object (Firefox devtools), и вы увидите список методов.
Array.Prototype содержит методы
Firefox журналирует прототип как опытный образец
::: Примечание Оба __proto__ в Chrome и <Прототип> В Firefox указывает на объект прототипа. Они просто написаны по -разному в разных браузерах. :::
Когда вы используете карта , JavaScript ищет карта в самом объекте. Если карта не найден, JavaScript пытается найти прототип. Если JavaScript находит прототип, он продолжает искать карта в этом прототипе.
Итак, правильный Определение для прототипа есть: Объект, где экземпляры могут получить доступ Когда они пытаются искать собственность.
Прототип цепочек
Вот что делает JavaScript, когда вы получаете доступ к недвижимости:
Шаг 1 : JavaScript проверяет, есть ли свойство, доступное внутри объекта. Если да, JavaScript использует свойство сразу.
Шаг 2 : Если свойство не находится внутри объекта, JavaScript проверяет, есть ли прототип. Если есть прототип, повторите шаг 1 (и проверьте, находится ли свойство внутри прототипа).
Шаг 3 : Если прототипов больше не осталось, а JavaScript не может найти свойство, оно выполняет следующее:
- Возвращает
неопределенное(Если вы пытались получить доступ к недвижимости). - Бросает ошибку (если вы пытались вызвать метод).
Схематически, вот как выглядит процесс:
Пример цепочки прототипа
Допустим, у нас есть ЧЕЛОВЕК класс. У нас также есть Разработчик Подкласс, который наследует от ЧЕЛОВЕК Анкет ЧЕЛОВЕК S имеет Sayhello Метод и Разработчики иметь код метод
Вот код для Человек
class Human {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastname = lastName
}
sayHello () {
console.log(`Hi, I'm ${this.firstName}`)
}
}
::: Примечание ЧЕЛОВЕК (и Разработчик ниже) можно записать с функциями конструктора. Если мы используем функции конструктора, Прототип становится более ясным, но создание подклассов становится сложнее. Вот почему я показываю пример с классами. (См. Эта статья для 4 различных способов использования объектно -ориентированного программирования).
Вот как бы ты написал ЧЕЛОВЕК Если вы использовали конструктор вместо этого.
function Human (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
Human.prototype.sayHello = function () {
console.log(`Hi, I'm ${this.firstName}`)
}
:::
Вот код для Разработчик Анкет
class Developer extends Human {
code (thing) {
console.log(`${this.firstName} coded ${thing}`)
}
}
A Разработчик экземпляр может использовать оба код и скажи привет потому что эти методы расположены в цепочке прототипа экземпляра.
const zell = new Developer('Zell', 'Liew')
zell.sayHello() // Hi, I'm Zell
zell.code('website') // Zell coded website
Если вы Консоль.log Пример, вы можете увидеть методы в цепочке прототипа.
Прототипическое делегирование/прототипа наследование
Прототипная делегирование и прототипальное наследование означают одно и то же.
Они просто говорят, что мы используем систему прототипа – где мы помещаем свойства и методы в Прототип объект.
Должны ли мы использовать прототипную делегирование?
Поскольку JavaScript является языком на основе прототипов, мы должны использовать прототипную делегирование. Верно?
Не совсем.
Я бы сказал, что это зависит от того, как вы пишете объектно -ориентированное программирование. Имеет смысл использовать прототипы, если вы используете классы, потому что они более удобны.
class Blueprint {
method1 () {/* ... */}
method2 () {/* ... */}
method3 () {/* ... */}
}
Но имеет смысл не использовать прототипы, если вы используете заводские функции.
function Blueprint {
return {
method1 () {/* ... */}
method2 () {/* ... */}
method3 () {/* ... */}
}
}
Опять читай Эта статья Для четырех разных способов записи объектно -ориентированного программирования.
Последствия для производительности
Производительность между двумя методами не имеет большого значения – если ваше приложение требует миллионов операций. В этом разделе я собираюсь поделиться некоторыми экспериментами, чтобы доказать этот момент.
Настраивать
Мы можем использовать Производительность.now Чтобы зарегистрировать временную метку перед выполнением каких -либо операций. После запуска операций мы будем использовать Производительность.now Чтобы снова зарегистрировать метку времени.
Затем мы получим разницу в временных метках, чтобы измерить, сколько времени заняли операции.
const start = performance.now() // Do stuff const end = performance.now() const elapsed = end - start console.log(elapsed)
Я использовал Perf функция, чтобы помочь с моими тестами:
function perf (message, callback, loops = 1) {
const startTime = performance.now()
for (let index = 0; index <= loops; index++) {
callback()
}
const elapsed = performance.now() - startTime
console.log(message + ':', elapsed)
}
Примечание: вы можете узнать больше о Производительность.now в Эта статья Анкет
Эксперимент № 1: Использование прототипов против не использования прототипов
Во -первых, я проверил, сколько времени требуется, чтобы получить доступ к методу с помощью прототипа против другого метода, который находится в самом объекте.
Вот код:
class Blueprint () {
constructor () {
this.inObject = function () { return 1 + 1 }
}
inPrototype () { return 1 + 1 }
}
const count = 1000000
const instance = new Blueprint()
perf('In Object', _ => { instance.inObject() }, count)
perf('In Prototype', _ => { instance.inPrototype() }, count)
Средние результаты суммированы в этой таблице следующим образом:
| В объекте | 3 мс | 15 мс |
| В прототипе | 2 мс | 12 мс |
Примечание. Результаты из Devtools Firefox. Читать это Чтобы понять, почему я только сравниваю с Firefox.
Вердикт: не имеет значения, используете ли вы прототипы или нет. Это не изменится, если вы не запустите> 1 миллион операций.
Эксперимент № 2: Классы против заводских функций
Мне пришлось запустить этот тест, так как я рекомендую использовать прототипы, когда вы используете классы, и не использовать прототипы при использовании заводских функций.
Мне нужно было проверить, было ли создание заводских функций значительно медленнее, чем создание классов.
Вот код.
// Class blueprint
class HumanClass {
constructor (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
sayHello () {
console.lg(`Hi, I'm ${this.firstName}}`)
}
}
// Factory blueprint
function HumanFactory (firstName, lastName) {
return {
firstName,
lastName,
sayHello () {
console.log(`Hi, I'm ${this.firstName}}`)
}
}
}
// Tests
const count = 1000000
perf('Class', _ => { new HumanClass('Zell', 'Liew') }, count)
perf('Factory', _ => { HumanFactory('Zell', 'Liew') }, count)
Средние результаты суммированы в таблице следующим образом:
| Класс | 5 мс | 18 мс |
| Фабрика | 6 мс | 18 мс |
Вердикт: не имеет значения, используете ли вы класс или заводские функции. Это не изменится, даже если вы запустите> 1 миллион операций.
Заключение о тестировании производительности
Вы можете использовать классы или заводские функции. Вы решите использовать прототипы, или вы можете не делать этого. Это действительно зависит от вас.
Нет необходимости беспокоиться о производительности.
Спасибо за чтение. Эта статья была первоначально размещена на Мой блог Анкет Подпишитесь на мой информационный бюллетень Если вы хотите больше статей, чтобы помочь вам стать лучшим разработчиком Frontend.
Оригинал: “https://dev.to/zellwk/understanding-javascript-prototype-5187”