Опасные последствия стиля Allman в JavaScript
Я не могу вспомнить, где, но недавно я передал комментарий, в котором пользователь сказал, что 1TBS является более предпочтительным, чем Allman в JavaScript, и сказал, что Allman имеет опасные последствия для JavaScript.
Это было правильное утверждение? Если так, то почему?
5 ответов
return
не могу иметь LineTerminator
после этого так:
return
{
};
рассматривается как return;
(вернуть undefined
) вместо return {};
(вернуть объект)
Смотрите правила для Automatic Semicolon Insertion (ASI)
для большего.
Это правильное утверждение.
Потому что у движков JavaScript есть то, что называется ASI (автоматическая вставка точки с запятой), которая вставляет точку с запятой в случае необходимости в возвращаемые строки. "При необходимости" неоднозначно; иногда это работает, а иногда нет. Смотрите правила.
Итак, как сказано в других ответах:
return
{
};
// Is read by the JavaScript engine, after ASI, as:
return; // returns undefined
{ // so this is not even executed
};
Так что это не рекомендуется для return
заявления.
Однако, если ваши рекомендации рекомендуют стиль Allman для объявлений функций, это прекрасно. Я знаю некоторых, которые делают.
return {
a: "A",
b: "B"
};
// vs.
return // Semicolon automatically inserted here! Uh oh!
{
a: "A",
b: "B"
}
Я думаю, что это зависит от заявления. Например, оператор возврата может быть нарушен, если открывающая скобка находится на новой строке. Больше информации здесь.
Вы можете использовать стиль Allman или Allman-8, если вы помните один особый случай с ключевыми словами и .
Отделение литералов объектов от ключевых слов или перевода строки не работает в JavaScript из-за правил ASI, которые имеют специальное исключение для операторов и:
- Когда при анализе программы слева направо встречается токен, который разрешен некоторым производством грамматики, но производство является ограниченным производством, и токен будет первым токеном для терминала или нетерминала сразу после аннотации. « [здесь нет LineTerminator] » внутри ограниченного производства (поэтому такой токен называется ограниченным токеном ), и ограниченный токен отделяется от предыдущего токена хотя бы одним LineTerminator, то перед ограниченным токеном автоматически вставляется точка с запятой .
а также
ПРИМЕЧАНИЕ . Ниже приведены единственные ограниченные постановки в грамматике:
[...]
ReturnStatement :
[здесь нет LineTerminator] Expression ;
ThrowStatement :
[здесь нет LineTerminator] Expression ;
(Есть и другие ограниченные производства, но они не поддерживают фигурные скобки, поэтому они не важны для стиля Оллмана.)
На практике это не работает так, как вы ожидаете :
return
{
status: "successful",
user:
{
id: "9abf38a3-c2f5-4159-a1be-0eccbc1b2349",
label: "John Doe",
},
};
потому что это будет интерпретироваться как (обратите внимание на точку с запятой после возврата!)
return;
{
status: "successful",
user:
{
id: "9abf38a3-c2f5-4159-a1be-0eccbc1b2349",
label: "John Doe",
},
};
Итак, вы должны либо использовать синтаксис
const response =
{
status: "successful",
user:
{
id: "9abf38a3-c2f5-4159-a1be-0eccbc1b2349",
label: "John Doe",
},
};
return response;
или же
return {
status: "successful",
user:
{
id: "9abf38a3-c2f5-4159-a1be-0eccbc1b2349",
label: "John Doe",
},
};
вместо.
Я лично считаю, что имена возвращаемых структур в любом случае более читабельны, поэтому я использую это. Я также везде использую Allman-8, что практически означает, что вы используете 8 символов табуляции шириной пробела и отступаете всего одним символом табуляции вместо 1 или более пробелов.
Теоретически кто-то мог бы также написать
throw
{
status: "error",
code: 12,
details: localvar,
};
что также потерпит неудачу, потому что точка с запятой будет вставлена сразу после ключевого слова из-за приведенных выше правил ASI. В реальном мире все, кажется, пишут
throw new ...
или же
throw localvar
.
Я не знаю историю этих исключений, но могу только предположить, что это какая-то историческая ошибка, которую больше нельзя исправить из-за существующего реального кода, зависящего от этой ошибки. Я не вижу ни одной конструкции, в которой эта автоматическая точка с запятой была бы действительно полезной, поэтому я думаю, что это просто ошибка в исторической спецификации. (Код, следующий за
return
или же
throw
не может разумно начинать с литерала объекта, поэтому он все равно не будет работать со вставленной точкой с запятой.)