Pull to refresh

Открытое письмо лидерам JS касательно точек с запятой

Reading time 6 min
Views 5.2K
Original author: Isaac Z. Schlueter
Такое письмо я получил от Шона Сильвы прошлой ночью:
Я просматривал ваш код для проекта npm.js (в частности, вот этот файл: https://github.com/isaacs/npm/blob/master/lib/npm.js), и заметил, что вы выравниваете запятые под ‘r’ в выражениях var, и под [ и { в литералах массивов/объектов. Мне очень нравится такой способ форматирования, но я не решаюсь его использовать, так как большинство ресурсов о js насаждают страх перед хаосом, который воцарится в коде из-за автоматической расстановки точек с запятой, если вы не будете заканчивать строки чем-нибудь, что предполагает продолжение.
Безопасно ли располагать запятые таким образом в «браузерном» коде, или это только в node возможно?

Я написал несколько абзацев, и решил сократить их до следующего ответа:
Да, это полностью безопасно, и это совершенно валидный JS, понимаемый каждым браузером. Closure compiler, yuicompressor, packer, и jsmin — все могут правильно минифицировать его. Производительность нигде не просядет.
Мне жаль, что вместо того, чтобы обучать вас, лидеры сообщества этого языка прививали вам ложь и страхи. Это позор. Я рекомендую изучить, как на самом деле терминируются инструкции в JS (и в каких случаях они нетерминируемы) — и вы сможете писать код, который сочтете прекрасным.


Inimino запостил очень четкое объяснение. В его стиле — четкое, ясное, авторитетное, с хорошим исследованием, — и он, как всегда, оставил свое мнение при себе.
Я собираюсь быть немножко более пристрастным.

Правила

В общем и целом, \n всегда заканчивает выражения, за исключением следующих случаев:
  • Выражение несет незакрытую круглую скобку, литерал массива, литерал объекта или заканчивается любым другим способом, который не является легальным способом закрыть выражение (например, кончается на . или ,);
  • Строка представляет из себя --, ++ (в том случае, если следующий токен будет декрементирован/инкрементирован);
  • Это for(), while(), do, if(), или else, и на строке нет {
  • Следующая строка начинается с [, (, +, *, /, -, ,, ., или любого бинарного оператора, который может находиться в одном выражении только между двумя токенами.

Первое правило довольно очевидно. Даже JSLint не возражает против символов \n в JSON, в конструкциях со скобками, и в var-выражениях, которые простираются на несколько строк, кончающихся на ,.
Второе — очень странное. Я никогда не встречал таких вещей (за исключением такого рода бесед), чтобы кто-то хотел написать i\n++\nj, но, по факту, это парсится как i; ++j, а не как i++; j
Третье хорошо понимают, хотя обычно пренебрегают им: if (x)\ny() эквивалентно if (x) { y() }. Эта конструкция не заканчивается, пока не будет встречен блок или выражение. ; является валидным выражением JavaScript, так что if(x); эквивалентно if(x){} или «если x, ничего не делать.» Это обычно применяется к циклам, в которых проверка является также обновлением счетчика. Необычно, но встречается.
Четвертое, обычно, внушающий FUD, «ох неты, тебе нужны точки с запятой!»-случай. Но, оказывается, довольно просто предварить такие строки точками с запятыми, если вы не хотели сделать их продолжениями предыдущих.
Например, вместо:
foo();
[1,2,3].forEach(bar);
можно написать:
foo()
;[1,2,3].forEach(bar)

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

Ограниченное правило

Еще один стандартный аргумент в пользу точек с запятой имеет отношение к AIS и ограниченным правилам. К примеру, если у вас стоит \n сразу после токена return, throw, break, continue, или ++ или -- в постфиксной форме (например, x++\n или y--\n), то сие закончит выражение — без исключения.
//ок
return 7

//вероятно, ошибка
return
       7
И еще раз: несмотря на это, заметить и предовратить такие вещи проще, как только вы отвыкнете завершать каждое выражение точкой с запятой. Когда я встречаю второе правило, мой мозг инстинктивно ассоциирует \n c «ок, с этим всё», потому что для терминации return всегда достаточно только перевода строки.
Выравнивание важнейших токенов в левой части экрана делает их явно более легкими для быстрого анализа человеком. Кипы исследований быстрого чтения и движений глаз утверждают, что отсутствующий токен справа проглядят с большей вероятностью, чем отсутствующий токен слева. Так что — я повторюсь — перемещайте менее важные вещи направо, а слева ставьте более важные вещи.

Так какой стиль лучше?

В той мере, в какой вообще существует объективно «лучший стиль», мне кажется, что стиль «минимум точек с запятыми/запятые первыми» — слегка лучше; по двум причинам: потому что этот стиль лучше читается и потому что он поощряет разработчиков лучше понимать язык, который они используют.
Я могу гарантировать, что, как бы мало вас это не волновало, меня ваш JS-код волнует меньше, чем мой — вас. Это не та статья, где я пытаюсь убедить вас писать код в моем стиле. Каждый сам должен решить, какова политика ношения штанов в его доме.
Как проявление доброй воли…

Хорошие причины ставить точки с запятой

Причины для избыточного использования точек с запятой — эстетика и политика.
«Я ставлю точки с запятой в JS, потому что иначе это не будет валидным C/C++/Java/Ещечёмто». Если вы вынуждены писать много Java- или C-кода в проекте, и хотите, чтобы ваш JS не слишком выделялся — то это достойный довод. (Проект Cassis доводит этот довод до абсурдного завершения).
«Мы так делаем, потому что используем линтер, и линтер велит так». Консистентность — важна, и линтеры — один из способов достижения консистентности кода для группы. Задача написания линтера, совместимого с npm, стоит в моем todo-листе, но не очень высоко.

Cамые ужасные причины везде ставить точки с запятой

«Они обязательны, потому что ASI — ненадежно» О, да ладно??
Эти правила восходят к заре JS, к поздним 90-м. Они не новы, и мое мнение — нет прощения никому, называющему себя профессионалом в JS и не понимающему правила прерывания выражений. Это откровенно безответственно со стороны лидеров сообщества JS — продолжать распространять неясность вместо понимания.
Более того, типичное место, где AIS нападает исподтишка — ограниченные правила. Добавление точек с запятой в каждой строчке не заставит return\nfoo возвращать что-то, кроме undefined. Проблема в том, что вы используете перевод строки, а не в том, что вы не ставите точки с запятой.
Единственный способ навсегда предотвратить ошибки с ограниченными правилами — всегда использовать точки с запятой и никогда не ставить переносы строки. Никто этого не предлагает. Так что перестаньте говорить об этом так, будто это имеет значение, или предлагать избыточные точки с запятой как альтернативу пониманию ASI. Вы обязаны понимать ASI, чтобы быть компетентным JS-программистом, точка.
И это приводит нас к тому, что…

Я становлюсь весь из себя необъективный и взбешиваю вас (несмотря на благородную попытку сделать противоположное)

Если вы не понимаете, как терминируются выражения в JS, то вы просто-напросто не знаете JS как следует, и не должны профессионально писать на JS без надзора, и определенно не должны давать советы о том, как на нем писать.
Думаю, я только что оскорбил вас. Очень жаль. Я знаю, что вы знаете множество вещей, касающихся JS — таких, как DOM, и CSS, и баги MSIE, и jQuery. Вы, вероятно, потратили некоторое время, изучая замыкания, и прототипы, и области видимости, и объекты активации, и даже написали несколько расширений для V8 или SpiderMonkey. Вы не глупы, я уверен. На самом деле, вы, скорее всего, умнее меня, и, наверное, более милы и лучше выглядите. Я уверен: у нас много общего, и мы могли бы быть друзьями.
Но если вы не понимаете, что из себя представляет выражение в JS, то в вашем понимании того, что, возможно, является самым фундаментальным аспектом языка — огромная дыра.
И это нормально. Я не очень хорошо говорю на испанском и мой C, в общем, на уровне новичка; и я не называю себя экспертом в этих вещах, — хотя и знаю достаточно, чтобы выкрутиться в большинстве ситуаций. Если бы я собирался на работу, которая подразумевает много разговоров на испанском или много C — я бы хотел, чтобы за мной присматривал кто-нибудь, дабы помочь избежать каких-то серьезных ошибок.
Как и большинство вещей в JS, правила терминирования выражений не очень хорошо спроектированы, но они и не очень трудны для понимания и использования. Это понимание просто требует немножко времени и усилий.
Устройтесь поудобнее с горячим шоколадом и спецификацией ECMAScript как-нибудь субботним вечером. Попрактикуйтесь. Поиграйте с тестовыми программами. Это хорошее времяпрепровождение.
Или не делайте этого, если не хотите. Это ваша жизнь. Наверняка у вас есть занятия получше.
Только перестаньте делать авторитетные заявления типа «заканчивайте все строки точками с запятой, чтобы быть в безопасности». Это ничуть не безопаснее и не надежнее.

Дополнение 1: «Лидеры»

Так, мистер-гладящий-против-шерсти, кто же эти «лидеры», о которых вы говорите? Почему вы не называете имен?

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

Дополнение 2: Адепты Грамотного Программирования

(прим. переводчика: имеется ввиду literary programming)
Но в английском языке мы ставим знаки препинания в конце, а не в начале.

JavaScript — это не английский. Мы так же не обозначаем владение (или отношение объект-глагол) с помощью точки в английском. В английском нет литералов объектов, и мы делаем отступ только в первой строке абзаца, а не во всех предложениях.
Это такой глупый довод, что у меня нет выбора, кроме того, чтобы влюбиться в в него.
Я начал вас оскорблять, но вы завоевали мое сердце, Адепт Грамотного Программирования. С этого момента я буду ставить переводы строки только в конце функций, не в середине, и делать отступ на первой строке каждой из них.

Дополнение 3: Педантизм

Чо ты лезешь в мой код? Ты чо педант штоле?

Пишите код, как хотите. Мне нет ни малейшего дела.
Просто, пожалуйста, не лгите людям. Это все, чего я прошу. Это лишь небольшая вежливость. Это не сложно. Просто говорите правду вместо лжи — вот о чем я говорю.

(от переводчика: как переводчик, хочу выразить благодарность за помощь с переводом и корректорскую работу своей любимой женщине — филологу)
Tags:
Hubs:
+42
Comments 109
Comments Comments 109

Articles