Есть ли на каком-либо другом языке, кроме JavaScript, разница между начальными местоположениями скобок (та же строка и следующая строка)?

91

Сегодня, когда я случайно читал книгу О'Рейли по шаблонам JavaScript, я обнаружил одну интересную вещь (стр. 27 для справки).

В Javascript в некоторых случаях есть разница, если место начала фигурной скобки отличается.

function test_function1() {
    return
    {
        name: 'rajat'
    };
}

var obj = test_function1();
alert(obj);  //Shows "undefined"

Пока

function test_function2() {
    return {
        name: 'rajat'
    };
}

var obj = test_function2();
alert(obj); //Shows object

Демо JSfiddle

Есть ли в других языках такое поведение? Если так, то мне обязательно придется менять привычку .. :)

Меня больше всего беспокоят PHP, C, C ++, Java и ruby.

Раджат Сингхал
источник
1
Воспроизведено в Chrome и IE9, удачный улов: P
gideon
4
Чувствительность к пустому пространству можно заставить работать - посмотрите на питон или линейный режим fortran - но тонкая чувствительность к пустому пространству - это работа дьявола. Ага! Это так же плохо, как и сделать!
dmckee --- котенок экс-модератора
Это впечатляет! Хорошая находка!
CheckRaise
Теперь я хочу знать, почему javascript так себя ведет.
CheckRaise
4
@CheckRaise: Я суммирую правила здесь: blogs.msdn.com/b/ericlippert/archive/2004/02/02/…
Эрик Липперт

Ответы:

53

Любой язык, который не полагается на точки с запятой (а вместо этого на новые строки) для разделения операторов, потенциально допускает это. Рассмотрим Python :

>>> def foo():
...   return
...   { 1: 2 }
... 
>>> def bar():
...   return { 1: 2 }
... 
>>> foo()
>>> bar()
{1: 2}

Вы могли бы создать аналогичный случай в Visual Basic, но я не могу понять, как это сделать, потому что VB довольно ограничен в том, где могут быть размещены значения. Но следующее должно работать, если только статический анализатор не жалуется на недостижимый код:

Try
    Throw New Exception()
Catch ex As Exception
    Throw ex.GetBaseException()
End Try

' versus

Try
    Throw New Exception()
Catch ex As Exception
    Throw
    ex.GetBaseException()
End Try

Из упомянутых вами языков Ruby имеет то же свойство. PHP, C, C ++ и Java не делают этого просто потому, что они отбрасывают новую строку как пробелы и требуют точки с запятой для разделения операторов.

Вот эквивалентный код из примера Python на Ruby:

>> def foo
>>   return { 1 => 2 }
>> end
=> nil
>> def bar
>>   return
>>   { 1 => 2 }
>> end
=> nil
>> foo
=> {1=>2}
>> bar
=> nil
Конрад Рудольф
источник
2
Ваш пример VB не совсем отражает суть, потому что VB никогда не позволяет оператору занимать несколько строк, если вы не используете последовательность продолжения строки "_".
phoog
2
Хорошо, я отказываюсь от предыдущего комментария, потому что я только что посмотрел на спецификацию, есть некоторые контексты, в которых VB.NET поддерживает неявное продолжение строк. Я сомневаюсь , что любой опытный программист VB будет рассматривать этот пример с «Гоча», однако, так как это довольно очевидно , что Throwи ex.GetBaseException()отдельные логические линии. В частности, поскольку Basic исторически использует строки для разграничения своих операторов, «ошибка», скорее всего, будет ситуацией, когда программист думает, что он создал новый оператор в новой логической строке, но не сделал этого.
phoog
@phoog Верно, это совсем не ошибка.
Конрад Рудольф
40

Интерпретатор JavaScript автоматически добавляет ;в конец каждой строки, если он не находит его (за некоторыми исключениями, здесь они не попадают :).

Таким образом, в основном проблема заключается не в расположении фигурных скобок (которые здесь представляют литерал объекта, а не в блоке кода, как в большинстве языков), а в этой маленькой «особенности», которая заставляет ваш первый пример использовать return ;=> undefined. Вы можете проверить поведение return в спецификации ES5 .

Для других языков с аналогичным поведением ознакомьтесь с ответом Конрада .

Алекс Чиминян
источник
5
Ответ получил много голосов, но на самом деле он неверен, извините. Объяснение хорошее, но исправьте ошибку.
Конрад Рудольф
То, что касается JavaScript, не является неправильным, поскольку он ведет себя так же, как и из-за вставки точки с запятой, которая принудительно undefinedвозвращает. Я написал немного о других языках с префиксом afaik , так что относитесь к нему с недоверием :).
Алекс Чиминиан
5
Но это неправда, что JS вставляет точку с запятой «в конце каждой строки» «за некоторыми исключениями»; а, как правило , не вставить точку с запятой, и есть лишь несколько случаев , когда это делает . Вот почему это вызывает так много ошибок.
ruakh
26

Несомненно. Язык программирования Google go демонстрирует очень похожее поведение (хотя и с разными эффектами). Как объясняется там:

Фактически, в формальном языке используются точки с запятой, как в C или Java, но они автоматически вставляются в конец каждой строки, которая выглядит как конец оператора. Вам не нужно набирать их самостоятельно.

..щипок ...

Такой подход позволяет получить чистый код без точек с запятой. Единственный сюрприз заключается в том, что важно помещать открывающую скобку такой конструкции, как оператор if, в ту же строку, что и if; если вы этого не сделаете, есть ситуации, которые могут не скомпилироваться или дать неправильный результат. Язык в некоторой степени заставляет использовать стиль скобок.

Втайне я думаю, что Роб Пайк просто хотел оправдание, чтобы потребовать стиль One True Brace.

Дэйв
источник
10
Круто, не знала об этом :). Лично я не думаю, что автоматическая вставка точки с запятой - хорошая идея. Это может привести к появлению тонких ошибок, которые людям, не знакомым с языком, будет сложно выяснить. Если вы хотите писать код без точек с запятой, я предпочитаю путь Python.
Алекс Чиминиан
@Alex Даже языки без какой - либо точки с запятой (VB) обладают этим свойством. И Python, который вы, по-видимому, предпочитаете, хотя он обрабатывает это так же, как JavaScript.
Конрад Рудольф
Я бы проголосовал за, за исключением того, что ваше второе предложение настолько неверно, что мне хочется проголосовать против. Я думаю, они отменяются. ;-)
ruakh
1
@ruakh ты имеешь в виду "иди делает именно это" или ты имел ввиду анекдот про грабить пайка? В первом случае я мог бы перефразировать словами «иди демонстрирует такое же поведение», во втором - извините, если мое слабое чувство юмора оскорбляет;)
Дэйв
1
Я имею в виду «Go делает именно это». Первоначальное предложение по вставке точки с запятой в Go явно контрастирует с предложением JavaScript, поясняя: «Это предложение может напоминать вам о необязательном правиле точки с запятой в JavaScript, которое, по сути, добавляет точки с запятой для исправления ошибок синтаксического анализа. Предложение Go существенно отличается», а именно: Совершенно верно, на каждом уровне: он работает по-разному, имеет разные эффекты и почти не имеет ошибок. (Применение OTBS, хоть и раздражает, но не проблема, поскольку это постоянное требование во всем коде Go.)
ruakh
14

Ответить на этот вопрос довольно просто. Любой язык, в котором есть "автоматическая вставка точки с запятой", может вызвать ошибку в этой строке. Проблема с этим

return
{
     name: 'rajat'
};

.. заключается в том, что движок js вставит точку с запятой после return;оператора (и, следовательно, вернет undefined). Этот пример - хорошая причина открывать фигурные скобки всегда с правой стороны, а не с левой. Поскольку вы уже правильно заметили, если в той же строке есть фигурная скобка, интерпретатор заметит это и не сможет вставить точку с запятой.

Дженди
источник
6

FWIW, JSLint сообщает несколько предупреждений с этим синтаксисом:

$ jslint -stdin
function foo(){
  return
  { x: "y" };
}
^D
(3): lint warning: unexpected end of line; it is ambiguous whether these lines are part of the same statement
  return
........^

(3): lint warning: missing semicolon
  { x: "y" };
..^

(3): lint warning: unreachable code
  { x: "y" };
..^

(3): lint warning: meaningless block; curly braces have no impact
  { x: "y" };
..^

(3): lint warning: use of label
  { x: "y" };
.....^

(3): lint warning: missing semicolon
  { x: "y" };
...........^

(3): lint warning: empty statement or extra semicolon
  { x: "y" };
............^


0 error(s), 7 warning(s)
Brandan
источник
1

Первым языком, на котором я столкнулся с этим, был awk (который также имеет свою долю синтаксических «странностей»; необязательные точки с запятой, конкатенация строк с использованием только пробелов и т. Д.) Я думаю, что разработчики DTrace, которые основывали синтаксис D свободно на awk, хватило ума НЕ копировать эти функции, но я не могу припомнить. Простой пример (подсчет количества тегов ENTITY в DTD с моего Mac):

$ cat printEntities.awk 
# This prints all lines where the string ENTITY occurs
/ENTITY/ {
  print $0
}
$ awk -f printEntities.awk < /usr/share/texinfo/texinfo.dtd | wc -l
     119

Если бы этот небольшой сценарий был написан с фигурной скобкой на отдельной строке, то произошло бы следующее:

$ cat printAll.awk 
# Because of the brace placement, the print statement will be executed
# for all lines in the input file
# Lines containing the string ENTITY will be printed twice,
# because print is the default action, if no other action is specified
/ENTITY/
{ 
   print $0 
}
$ awk -f printAll.awk < /usr/share/texinfo/texinfo.dtd | wc -l
     603
$ /bin/cat < /usr/share/texinfo/texinfo.dtd | wc -l
     484
$ 
Андерс С
источник