Автор статьи, перевод которой мы сегодня публикуем, решил поделиться с читателями семью рекомендациями по JavaScript. Эти рекомендации, как хочется надеяться автору, помогут писать более надёжные программы.
1. Используйте фабричные функции
Если кто не знает, фабричная функция — это обычная функция (не класс и не конструктор), которая возвращает объекты. Эта простая концепция позволяет нам воспользоваться полезными возможностями JavaScript для создания мощных и надёжных приложений.
Важно знать о том, что фабричная функция вызывается без использования ключевого слова new
. Если вызвать её с данным ключевым словом, она перестанет вести себя так, как должна.
▍Зачем пользоваться фабричными функциями?
Фабричные функции могут быть использованы для упрощения создания экземпляров объекта без необходимости связываться с классами или с ключевым словом new
.
Суть фабричных функций в том, что их рассматривают как самые обыкновенные функции. Это означает, что они могут использоваться для конструирования объектов, других функций и даже промисов. То есть, такие функции можно сочетать и комбинировать для создания более мощных фабричных функций, которые, в свою очередь, тоже можно, объединяя с другими функциями или объектами, применять для создания ещё более продвинутых фабричных функций. Фабричные функции открывают перед программистом безграничные возможности.
Если учесть вышесказанное и совместить использование фабричных функций с рекомендованными подходами по написанию кода, эти функции способны стать мощнейшими и удобнейшими инструментами.
Вот простой пример фабричной функции:
function createFrog(name) {
const children = []
return {
addChild(frog) {
children.push(frog)
},
}
}
const mikeTheFrog = createFrog('mike')
Если некоторое время пользоваться фабричными функциями, можно прийти к пониманию того, что, в сравнении с их конкурентами в виде функций-конструкторов, фабричные функции способны повысить уровень повторного использования кода. В результате программисту приходится писать меньше кода. Фабричные функции облегчают рефакторинг, так как они способны возвращать произвольные объекты, и упрощают работу над кодовой базой.
2. При написании функций-конструкторов добавляйте методы к их прототипам
Если вы только недавно начали осваивать JavaScript, то работа с прототипом объекта может показаться вам чем-то новым. Так, в самом начале, было и со мной.
Учитывайте то, что эта методика не подходит для классов. Классы, без дополнительных усилий со стороны программиста, самостоятельно сохраняют методы в своих прототипах.
Вот пример функции-конструктора:
function Frog(name, gender) {
this.name = name
this.gender = gender
}
Frog.prototype.leap = function(feet) {
console.log(`Leaping ${feet}ft into the air`)
}
Зачем пользоваться конструкцией Frog.prototype.leap
вместо того, чтобы просто записать метод leap
в создаваемый конструктором объект? Например — так:
function Frog(name, gender) {
this.name = name
this.gender = gender
this.leap = function(feet) {
console.log(`Leaping ${feet}ft into the air`)
}
}
Дело в том, что если метод прикрепляется напрямую к свойству конструктора prototype
— это значит, что данный метод будут совместно использовать все экземпляры объекта, созданные конструктором.
Другими словами, если опираться на предыдущий пример, в котором используется this.leap
, то окажется, что при создании нескольких экземпляров объекта Frog
у каждого из них будет собственный метод leap
. То есть — будет создано несколько копий этого метода. В данном случае это говорит о нерациональном использовании системных ресурсов, так как во всех этих объектах будет присутствовать копия одного и того же метода, который везде ведёт себя одинаково. Создавать копии такого метода в каждом из экземпляров объекта не нужно.
В итоге это приведёт к ухудшению производительности программы. А ведь этого несложно избежать. Надо отметить, что свойства this.name
и this.gender
должны быть объявлены именно в таком виде, так как они должны принадлежать конкретному объекту. Если провести аналогию с настоящими лягушками, виртуальное представление которых описано с помощью конструктора Frog
, то окажется, что у лягушек могут быть собственные имена, лягушки имеют разный пол. Как результат — для хранения в каждом из объектов уникальных сведений о лягушках свойства объектов имеет смысл объявлять так, чтобы они использовались бы именно на уровне экземпляров объектов.
Вот пример использования этой методики в популярном пакете request.
3. Добавляйте к объектам, которые нужно различать, свойство .type
Свойство .type
, которое, по неофициальному соглашению, часто добавляют к объектам, нашло в наши дни чрезвычайно широкое применение. Если вы пишете React-приложения, то вы, возможно, сталкиваетесь с этим свойством постоянно. Особенно — если применяете Redux.
Использование подобного подхода очень хорошо показывает себя в процессе разработки, так как он, кроме прочего, позволяет создавать самодокументирующийся код:
function createSpecies(type, name, gender) {
if (type === 'frog') {
return createFrog(name, gender)
} else if (type === 'human') {
return createHuman(name, gender)
} else if (type == undefined) {
throw new Error('Cannot create a species with an unknown type')
}
}
const myNewFrog = createSpecies('frog', 'sally', 'female')
4. Пользуйтесь TypeScript
TypeScript получил широкое распространение в JavaScript-сообществе благодаря тому, что этот язык даёт в руки программиста мощное средство для безопасной работы с типами, а также позволяет выявлять ошибки ещё до того, как они проявятся в работающем коде.
Применение TypeScript позволяет находить потенциальные ошибки на этапе компиляции кода, ещё до того, как код будет запущен. Если в коде что-то не так — при его компиляции будет выведено соответствующее уведомление.
Но типобезопасность и раннее выявление ошибок — это далеко не полный список причин применения TypeScript в любых ситуациях. Одной из замечательных особенностей TypeScript является то, что этот язык позволяет пользоваться новыми возможностями JavaScript ещё до того, как их реализация появится в основных браузерах. Дело в том, что TypeScript-код компилируется в JavaScript-код, поддерживаемый как современными, так и не самыми новыми браузерами.
5. Пишите тесты
Если вы работаете над проектом и серьёзно настроены на эту работу, то вам практически необходимо писать тесты. Это позволит сделать код более предсказуемым, позволит сделать его менее подверженным ошибкам. Это даст более высокий уровень уверенности в качестве кода при внесении в него изменений. Другими словами, если вы хотите, чтобы ваш код выдержал бы проверку временем, нет лучшего способа подготовки кода к этой проверке, чем написание тестов. Чем больше тестов имеется в вашем проекте — тем больше уверенности в коде у вас будет при развёртывании его в продакшне.
Если бы нужно было выделить лишь одну, самую важную, положительную черту тестов, что бы это было? Полагаю, это тот факт, что тесты помогают находить ошибки до их попадания в работающую программу. Какому программисту не хотелось бы обладать такой возможностью? Я, совершенно точно, от такого не отказался бы. Именно поэтому я и пишу модульные тесты для своих проектов.
Если вы только собираетесь приступить к созданию тестов для своего проекта — знайте о том, что в наши дни существует масса инструментов и фреймворков для организации тестирования кода. Вот хороший материал об этом.
6. Пишите настолько простые функции, насколько это возможно
Как все мы знаем, JavaScript без проблем позволяет создавать огромные функции, которые решают сразу множество задач.
Если вы — новичок в программировании, то вам это может показаться чем-то позитивным. О себе скажу, что в былые времена я прекрасно себя чувствовал, когда писал здоровенные куски кода, которые делали то, что мне было нужно. Это имело значение, преимущественно, для меня. Я увереннее чувствовал себя, когда видел, что мой код работает без проблем, уже не говоря о том, что мою уверенность в себе подкрепляло то, что я способен написать громадный блок хорошо работающего кода. Каким же наивным я был тогда!
Если вы хотите писать код, который будет легко поддерживать, код, который устроен просто и не слишком сильно подвержен ошибкам, то вам лучше всего стремиться к тому, чтобы ваши функции были бы как можно проще и меньше. Чем проще функция — тем легче тестировать её в изоляции от других частей системы.
Это особенно важно для тех, кто стремится использовать в своей работе принципы функционального программирования. В этой связи можно вспомнить об одном общеизвестном требовании к функциям: функция должна решать всего одну задачу и ей необходимо решать эту задачу очень хорошо.
7. Всегда помните о важности обработки ошибок при использовании JSON.parse и JSON.stringify
В JavaScript-программировании, при передаче JSON-данных методу JSON.parse
, надо учитывать то, что этот метод ожидает получить, в качестве первого аргумента, правильно оформленный JSON-код. Если этот метод получит JSON-материалы, с которыми что-то не так, он выбросит ошибку.
Опасность тут заключается в том, что передача JSON.parse
некорректного JSON-кода приводит к остановке приложения. На работе я недавно столкнулся с ситуацией, когда один из наших веб-проектов выдавал ошибки из-за того, что один из внешних пакетов не помещал JSON.parse
в блок try/catch
. Это заканчивалось сбоем при работе страницы, и мы никак не могли избавиться от проблемы до тех пор, пока не был исправлен код внешнего пакета. Происходило же всё это из-за того, что в коде, в процессе его работы, появлялась необработанная ошибка:
SyntaxError: Unexpected token } in JSON at position 107
Обрабатывая JSON-данные, поступающие в приложение из внешних источников, нельзя надеяться на то, что они будут правильно оформленными. Всегда нужно быть готовым к тому, что в них может встретиться что-то такое, что вызовет ошибку.
Итоги
Надеемся, приведённые здесь рекомендации по улучшению надёжности JavaScript-кода вам пригодятся.
Уважаемые читатели! Что вы посоветовали бы тем, кто хочет писать более качественный и надёжный код на JavaScript?
Автор: ru_vds