dr.Brain

doctor Brain

мир глазами веб-разработчика

Прототипы в JavaScript

Как прототипы в JavaScript влияют на время выполнения кода?

dr.Brain

время чтения 3 мин.

Photo by Tyler Milligan on Unsplash

Во времена своего обучения в университете, я заметил, что многие однокурсники, занимающиеся разработкой веб-приложений, не могут понять: зачем и как использовать прототипы в JavaScript.

Неспособность разобраться с этой проблемой крылась в предшествующем изучении C# и Java - языков, ориентированных на использование классов. Для того чтобы создать определенную логику приложения, приходилось начинать с создания классов со своими свойствами и методами. В свою очередь, свойства использовались для хранения значений, а методы - для совершения определенных действий.

Но JavaScript отличается и изначально не поддерживает такой функционал, так как является прототипо-ориентированным языком. Несомненно, ECMAScript 2015 в свое время представил несколько нововведений, позволяющих создавать классы и объекты, но это не более чем “синтаксический сахар”. Вот почему я хочу продемонстировать, как создавть классы и их экземпляры, не прибегая к ключевому слову class, и как правильно пользоваться прототипами.

Итак, приступим.


Для того, чтобы объявить класс необходимо всего лишь создать функцию (хорошей практикой будет использование верблюжьей нотации). В нашем примере класс называется Person:

function Person(name, lastName) {
    this.name = name;
    this.lastName = lastName;
    
    this.tellFullName = function() {
        console.log(this.name + ' ' + this.lastName);
    }
}

Теперь создадим новый объект: new Person('Alex', 'Gilbert');. Полагаю, Вы спросите: “Зачем нужны прототипы, если у нас уже есть класс со всем необходимым функционалом?” Конечно, такое утверждение будет верным, до тех пор пока мы не обнаружим, что каждый новый экземпляр класса Person при создании получит в свое подчинение все свойства и методы, которые, в свою очередь, будут занимать новые области памяти. А что делать, если мы хотим использовать один и тот же метод tellFullName класса Person для всех его экземпляров?

Прототипы: мы должны переподчинить методы и свойства, которые не должны изменяться при создании объекта, прототипу класса Person:

function Person(name, lastName) {
    this.name = name;
    this.lastName = lastName;
}
  
Person.prototype.tellFullName = function() {
    console.log(this.name + ' ' + this.lastName);
}

var p = new Person('Alex', 'Gilbert');
p.tellFullName(); // результат - 'Alex Gilbert'

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


Наконец, давайте оценим эффективность использования различных экземпляров класса.

Создадим два различных объекта:

  1. класс с прототипами - WithPrototyping
  2. класс без прототипов - NoPrototyping

    const methodsAmount = 1000;
    const instancesAmount = 3000;
    
    function NoPrototyping() {
        for (let i = 1; i <= methodsAmount; i++) {
            this['method_' + i] = function () { return 'From method ' + i; }
        }
    }
    
    function WithPrototyping() {
    }
    
    console.time('NO_PROTOTYPING_TIME');
    for (let i = 1; i <= instancesAmount; i++) {
        new NoPrototyping();
    }
    console.timeEnd('NO_PROTOTYPING_TIME');
    
    
    console.time('WITH_PROTOTYPING_TIME');
    for (let i = 1; i <= methodsAmount; i++) {
        WithPrototyping.prototype['method_' + i] = function () { return 'From method ' + i; }
    }
    
    for (let i = 1; i <= instancesAmount; i++) {
        new WithPrototyping();
    }
    console.timeEnd('WITH_PROTOTYPING_TIME');
    

Получены следующие результаты:

  1. NO_PROTOTYPING_TIME: 885.98193359375ms
  2. WITH_PROTOTYPING_TIME: 0.743896484375ms

Можно сделать вывод, что переподчинение свойств и методов экземпляра класса прототипу позволяет увеличить скорость работы приложения.

Будьте внимательны. Большие цепочки прототипов уменьшают производительность приложения из-за расходования ресурсов на процесс поиска.

Еще больше информации о наследовании и цепочках прототипов можно узнать здесь


Спасибо за внимание.

Новые публикации

Далее

Категории

О нас

Frontend & Backend. Статьи, обзоры, заметки, код, уроки.