Не все функции созданы одинаковыми. Класс — это набор каким-то образом связанных друг с другом функций. Они могут принадлежать одной категории и иметь что-то общее в том, что выполняют.
В любом случае иногда лучше писать функции как метод объекта.
Сам 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 следует методологии прототипа, значит вы можете использовать классы для наследования. Он использует функции в качестве конструкторов для методов и объектов, то есть объединение функций в класс является способом логически организовать ваши мысли и бизнес-правила таким образом, чтобы все они были связаны друг с другом.
Заключение
Не всё должно быть классом, но существует немало кода, который стоило бы поместить в классы.
Объединение связанных функций в класс и превращение его в явный объектно-ориентированный шаблон помогает повысить модульность кода и возможность его многократного использования.
При отладке наличие чётких границ и установленных связей между различными частями кода помогает в определении проблемных зон и ошибок в логике быстрее, чем попытки отследить области видимости и наследования.
Читайте также:
- Чистый код JavaScript: обработка ошибок
- Да не нужен вам фреймворк JavaScript!
- Отображение нативных всплывающих окон с помощью API уведомлений JavaScript
Перевод статьи Aphinya Dechalert: 5 Reasons Why You Should Collate Your Functions Into a Class