Автоматическая вставка точки с запятой (ASI) в JavaScript
Я много лет так или иначе работаю с JavaScript и тем не менее, ко мне недавно обратились с достаточно простой ошибкой, описание которой меня с непривычки вначале слегка озадачило, но при более внимательном взгляде, проблема стала вполне очевидной. Приведу ее упрощенный пример:
console.log('blablabla')
(() => true)() // => ERROR: Uncaught TypeError: console.log(...) is not a function
Описание ошибки в этом примере может несколько сбить с толку, хотя по настоящему ошибка заключается просто в пропущенной точке с запятой в конце console.log('blablabla');, т.е. корректный вариант должен выглядеть как-то так:
// Этот код отработает корректно
console.log('blablabla');
(() => true)();
Для тех, кто с JavaScript малознаком, поясню. Суть в том, что в JavaScript явное указание точки с запятой является необязательным благодаря механизму автоматической вставки точки с запятой (ASI - Automatic Semicolon Insertion), который представляет собой набор правил, согласно которым интерпретатор неявно сам определяет конец выражения (т.е. как-бы за вас автоматически ставит точку с запятой). С правилами ASI вы можете ознакомиться в спецификации ECMAScript.
Честно говоря, я никогда не парился за такие ошибки ранее, просто потому что я всегда ставил точку с запятой в качестве явного завершения выражения (ну и по возможности требовал с других того же). Эта привычка у меня осталась еще со времен активной разработки на PHP. Ну и плюсом я стал явно избалован использованием TypeScript, стайлгайдов, линтеров и просто строгих правил.
Тем не менее, есть немало противников точки с запятой в JS. Кому-то просто лень ее ставить, ну типа не зря же придумали эту возможность. Но особенно меня прикалывают те разработчики которые говорят, что не ставят точку с запятой чисто из-за экономии времени на набор... И куда же столько сэкономленного времени тратится потом?
Почему я не рекомендую полагаться на ASI
Я всегда считал, что между очевидными и неочевидными правилами языка программирования, всегда нужно отдавать приоритет очевидности. Да, пусть это несколько многословней, но зато понятней при чтении, ибо зачастую код читают чаще чем пишут. И читать этот код могут другие программисты, которые не очень знакомы с особенностями ASI. Это касается не только оператора точки с запятой, но и тех же операторов сравнения == и === и многих других случаев.
В общем вот на мой взгляд несколько причин, в пользу явного обозначения точки с запятой:
- Единообразие в коде — не очень хорошо когда в одних частях кода есть точки с запятой, а в других они отсутствуют.
- Очевидность и читаемость — точка с запятой позволяет программисту явно обозначить конец выражения, причем не только для интерпретатора, но и для других программистов. В ином случае непонятно, отсутствие точки с запятой является ошибкой или это результат работы форматтера кода (того же Prettier), который может многострочно разложить длинную строку кода.
- Повышение надежности — тут см. пример в начале этой статьи. Помимо этого, на точку с запятой могут полагаться сторонние инструменты разработки, которые так или иначе анализируют код и могут неправильно распознать ASI.
Ну и кстати говоря, за явное обозначение точки с запятой стоят стайлгайды от AirBnB и Google (можно ознакомиться с русским переводом), которые писали люди с опытом и которые нередко берут за основу для использования в проектах.
Тем не менее, являясь сторонником явного обозначения точки с запятой, я не считаю необходимым ставить ее абсолютно везде. Допустим вполне необязательно ее ставить после блока тела функции, метода, обьявления класса или после блоков управляющих операторов (if, for, while и т.д.), за некоторыми исключениями. Подобное поведение есть и в других Си-подобных языках, поэтому тут ничего нового, главное здравый подход и единый стиль. В этом плане я рекомендую прочитать про правила касаемые точки с запятой, которые используются в популярном линтере ESLint и то, какие там заданы значения по умолчанию.
Что может помочь не забыть использовать точку с запятой
Т.к. вполне нетрудно по невнимательности забыть точку с запятой, то полезным было бы использовать следующие инструменты:
- Typescript — который может выявить большую часть ошибок из-за пропущенной точки запятой еще на этапе статического анализа, а не в рантайме, как в случае с JS.
- Любой линтер — например ESLint, который можно настроить на конкретные правила (semi) использования точки с запятой. По умолчанию у него кстати практически везде (за некоторым исключением) требуется явное обозначение точки с запятой.
Тем не менее, анализаторы кода хоть и позволяют снизить уровень ошибок из-за отсутствия точки с запятой, но не гарантируют их. Поэтому кодревью все-таки тоже было бы неплохо иногда проводить.
Заключение
Знаете, в каждом языке есть достаточно подводных камней. Такие вещи, как стайлгайды (например Google TypeScript Style Guide), соглашения (PEP-8, PSR, ...), преднастроенные линтеры и т.д., строятся на опыте множества разработчиков и позволяют вам избежать тех проблем, о которых вы можете даже и не догадываться.
В любом случае, нужно придерживаться тех правил, которые уже приняты в проекте. Если в сопровождаемом стайлгайде указано полагаться на ASI, тогда не указывайте точку с запятой. В любом другом случае, если в проекте не запрещено, то лучше все-таки явно указывать точку с запятой.