Чи є у будь-якої іншої мови, крім JavaScript, різниця між початковими фігурними дужками (той самий рядок і наступний рядок)?


91

Сьогодні, коли я випадково читав книгу O'Reilly про 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

Із зазначених вами мов Рубі має таку ж властивість. 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 історично використовує рядки для розмежування своїх тверджень, "gotcha", швидше за все, буде ситуацією, коли програміст вважає, що він створив нову заяву на новому логічному рядку, але ні.
phoog

@phoog Правда, це абсолютно не проблема.
Конрад Рудольф

40

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

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

Для інших мов, які мають подібну поведінку, перевірте відповідь Конрада .


5
Високо оцінена відповідь, але насправді це неправильно, вибачте. Пояснення приємне, але, будь ласка, виправте помилку.
Конрад Рудольф

Частина про JavaScript не є помилковою, її поведінка так само, як і внаслідок вставки крапки з комою, яка змушує undefinedповертатися. Я писав трохи про інші мови з префіксом afaik , тож сприйміть це з достатньою кількістю солі :).
Alex Ciminian

5
Але це неправда, що JS вставляє крапку з комою "в кінці кожного рядка" "за деякими винятками"; швидше, він зазвичай не вставляє крапку з комою, і є лише кілька випадків, коли він це робить . Ось чому це викликає стільки неприємностей.
ruahh

26

Напевно. Мова програмування go від Google демонструє дуже подібну поведінку (хоча і з різними ефектами). Як там пояснено:

Насправді відбувається те, що офіційна мова використовує крапку з комою, подібно до C або Java, але вони вставляються автоматично в кінці кожного рядка, що виглядає як кінець висловлювання. Не потрібно набирати їх самостійно.

..ніп ...

Такий підхід робить чистий на вигляд код без крапки з комою. Одним сюрпризом є те, що важливо розмістити відкриваючу дужку конструкції, такої як оператор if, у тому самому рядку, що і if; якщо ви цього не зробите, трапляються ситуації, які можуть не скомпілюватися або можуть дати неправильний результат. Мова певною мірою змушує брекет-стиль.

Таємно, я думаю, що Роб Пайк просто хотів виправдання, щоб вимагати єдиного стилю брекетів.


10
Класно, не знав про це :). Особисто я вважаю, що автоматичне вставлення крапки з комою не є хорошою ідеєю. Це може спричинити витончені помилки, які людям, не досвідченим у цій мові, буде важко зрозуміти. Якщо ви хочете написати вільний код з комою, я віддаю перевагу способу python.
Alex Ciminian

@Alex Навіть мови без будь - яких точки з коми (VB) володіють цією властивістю. Як і Python, якому ви, мабуть, віддаєте перевагу, хоча він обробляє це ідентично JavaScript.
Конрад Рудольф

Я б підтримав, за винятком того, що ваше друге речення настільки неправильне, що викликає у мене бажання проголосувати проти. Я думаю, вони скасовують. ;-)
ruakh

1
@ruakh ти маєш на увазі "йди робиш саме це" або ти мав на увазі жарт про пограбування щуки? У першому випадку я міг би переформулювати слово "йти виявляє однакову поведінку", в другому - вибачте, якщо моє кульгаве почуття гумору ображає;)
Дейв,

1
Я маю на увазі "Go виконує саме це". Оригінальна пропозиція щодо вставки крапки з комою Go явно контрастує з пропозицією 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.