Есть ли на каком-либо другом языке, кроме 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)

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
$ 
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.