Пять причин поместить функции в класс

JavaScript

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

В любом случае иногда лучше писать функции как метод объекта. 

Сам JavaScript построен вокруг объектной идеи, даже если это не очевидно с первого взгляда. 

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

Краткий экскурс в классы JavaScript

Класс в JavaScript — это тип функции. В обычных обстоятельствах вы запишете функцию так: 

function catName(){
   console.log("Tibbers");
}

Стрелочная функция будет выглядеть так: 

catName = () => console.log("Tibbers");

Это всё хорошо, но что если у вас есть функции, связанные с cat? Если вам захочется присоединить функции cat к какому-либо инстансу? А если вы хотите сделать это так, чтобы вам не пришлось выяснять и сообщать коду, к какому инстансу относится функция?

И вот здесь пригодятся классы. 

Класс обычно состоит из двух частей — attributes и methods.

attributes определяет значения конкретного инстанса класса. methods делают что-то с этими attributes.

attributes — задаются в constructor, а methods обычно представлены в форме функций, расположенных внутри класса. 

Таким образом, класс выглядит примерно так:

class Cat{
  constructor(name, age, sound){   
      this.name = name; 
      this.age = age; 
      this.sound = sound; 
  } 

speak = () => console.log(this.sound);

name = () => console.log('hello, my name is ' + this.name);

age = () => console.log('I am ' + this.age);
}

И так выглядят 80% классов в JavaScript. Остальные 20% имеют дело с расширениями и различными способами структурирования классов, что выходит за рамки этой статьи.

Главный вопрос, на который мы пытаемся ответить: зачем вообще помещать функции в класс вместо того, чтобы просто оставлять их в коде?

Организованные функции более функциональны 

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

Когда вы пишете класс, вы создаёте другой уровень организации кода. 

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

Вы можете написать одно и то же несколькими способами, и все они будут работать. 

Таким образом, проблема становится организационной. 

Функция — это организационная методология. Класс просто делает шаг вперёд. 

Всё — объект

JavaScript построен на идее прототипов. Это означает, что код запускается как единая глобальная область видимости, которая разбивается на меньшие изолированные области, которые в свою очередь тоже разделяются на меньшие. 

На диаграмме это выглядит так:

attributes наследуются от родительского элемента к дочернему. 

Поэтому, когда объект, находящийся ниже по цепочке, хочет что-то, он запрашивает это у родительского объекта. Если у родителя этого нет, процесс продолжается вверх по цепочке, пока не будет найдено искомое или не вернётся undefined.

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

Почему не задать всё как глобальную области видимости? 

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

Защита от мутаций

Существует заблуждение: чтобы защитить переменные от мутаций, нужно закрыть их для изменения. Однако мутации зависят от формы переменной, а не от самой переменной. Значение переменной может меняться, форма— нет. Например, посмотрим на следующий объект: 

Tibbers = { name: "Tibbers", type: "cat", color: "ginger" }

Этот объект в текущем виде не защищён от мутаций. Почему? Потому что можно сделать следующее: 

Tibbers.owner = "Aphinya";

Мы изменяем форму объекта, добавив другую пару ключ-значение. Предотвратить это можно, создав объект Tibbers с помощью класса. Вы можете попробовать передать новое значение, но ничего не произойдёт. 

Почему это важно?

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

Контейнеризованный модульный принцип

Модульным может быть всё. Полезный модульный принцип связан с тем, насколько тесно ваши логические рассуждения связаны с конкретной идеей. Кто угодно может сказать, что его код модульный, ведь можно просто поместить код внутрь функции и назвать его модульным. 

Однако при использовании класса вы систематически подходите к модульности с укреплённой структурой и единой идеологией. По сути вы контейнеризуете свой код и объединяете свои функции таким образом, что превращаете их в семейство связанных функций. 

Именно этим являются методы в классе — набором функций, сгруппированных в зависимости от того, что они делают. 

JavaScript объектно-ориентирован

JavaScript по своему дизайну — это мультипарадигмальный язык с динамической типизацией. Это означает, что он не ограничивается одной идеологией структурирования логики кода. 

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

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

Заключение

Не всё должно быть классом, но существует немало кода, который стоило бы поместить в классы. 

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

При отладке наличие чётких границ и установленных связей между различными частями кода помогает в определении проблемных зон и ошибок в логике быстрее, чем попытки отследить области видимости и наследования.

Специально для сайта ITWORLD.UZ. Новость взята с сайта NOP::Nuances of programming