Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Декларация-вызов в JS

Сегодня на первой части семинара Ильи Кантора по JS присутствовал (к сожалению, на второй части не получится, буду в Москве это время). Немного поговорили о частом паттерне «объявили функцию и тут же вызвали». Используется этот приём (если кто не знаком с ДжаваСкриптом) для изоляции — в этом языке функции единственное, что может создавать зоны видимости.

Я вскользь затронул свой любимый способ — описание функции и вызов через восклицательный знак или тильду, вместо оборачивания скобками. Вообще, в JS непосредственный вызов функции сразу по месту определения возможен, только если декларация находится в контексте выражения. Для этого и нужны традиционные скобки:

(function () {
    // скобки вокруг функции говорят интерпретатору, что это выражение
})();

Вообще говоря, можно использовать любые средства, чтобы декларация стала частью выражения. Например, можно что-то прибавить к декларации. Или использовать любую унарную операцию.

Использование тильды или восклицательного знака гораздо лучше скобок по трём причинам:

!function () {
    // 
}();

Во-первых, на один байт меньше. Если таких функций много, экономия существенная. Во-вторых, скобки надо балансировать, а унарный оператор — нет.

И, в-третьих, самая главная причина. Вот такой код вызовет ошибку:

var a = 5
(function() {})()

Причём ошибку, которую найти иногда довольно трудно, да и сообщение о ней не самое дружественное: «TypeError: 5 is not a function». На самом деле, тут пропущена точка с запятой. Интерпретатор считает, что ему встретились две части выражения, между которыми пропущен какой-то знак. Эта ситуация часто встречается при автоматическом объединении двух скриптов в один.

Обычно для этого добавляют точку с запятой сразу перед такими блоками.

Но если использовать унарный оператор, то этой проблемы просто нет (поэтому, на самом деле, мы экономим два байта, ещё и точка с запятой не обязательна):

var a = 5
!function () {}()

Тут интерпретатор, встретив унарный оператор, понимает, что предыдущее выражение закончилось и началась новая конструкция.

33 комментария
yahoob 2012

Да, недавно наткнулся на такую ошибку, искал довольно долго.
Но мне кажется использование таких приемов и не расставления точек с запятых противоречит общепринятым код стандартам. Разве нет?

Fulcrum (fulc.ru) 2012

А какой смысл не использовать точки с запятой, кроме какого-нибудь спортивного программирования, где нужно уложиться в килобайт кода? И можно ли заметить разницу в размере кода в реальных ситуациях при экономии байтов? Польза от какого-нибудь сжимателя js будет гораздо больше.

Вот тут еще несколько граблей, на которые можно наступить, если не ставить точки с запятой: http://lucumr.pocoo.org/2011/2/6/automatic-semicolon-insertion/

Андрей 2012

Где именно то экономите 2 байта? ) JS-движки загружают в память все сырцы?

SiMM 2012

Офф: почему если я нажимаю ← старее http://bolknote.ru/write/236/ я имею в итоге всего две статьи?
PS: почему я не могу ответить лично автору? ;) В списке значатся варианты «всем» и трое отписавшихся.

Igor M Podlesny (poige.livejournal.com) 2012

в этом языке функции единственное, что могут создавать зоны видимости.

Может «может», а не «могут»? :-)

Азат Разетдинов (razetdinov.ya.ru) 2012

Похоже, ты пропустил недавнюю JS-драму с участием мэтров яваскрипта: http://jsdrama.com/

cssblast.ru 2012

By the  way
Ограничивать видимость можно еще такой модной штукой как let
https://developer.mozilla.org/en/New_in_JavaScript_1.7#let_statement

Евгений Степанищев (bolknote.ru) 2012

Комментарий для fulc.ru:

А какой смысл не использовать точки с запятой, кроме какого-нибудь спортивного программирования, где нужно уложиться в килобайт кода?

При аккуратном программировании лучше использовать точку с запятой. Жизнь сложнее. Иногда люди её пропускают.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для Андрей:

Где именно то экономите 2 байта? ) JS-движки загружают в память все сырцы?

В файле. Причём здесь JS-движки?

Евгений Степанищев (bolknote.ru) 2012

Комментарий для SiMM:

Офф: почему если я нажимаю ← старее http://bolknote.ru/write/236/ я имею в итоге всего две статьи?

Либо так, либо две статьи будут на последней странице.

PS: почему я не могу ответить лично автору? ;) В списке значатся варианты «всем» и трое отписавшихся.

А зачем? Я и так всё читаю.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для cssblast.ru:

Её всё равно что нет. Кроме FF кто её ещё поддерживает?

Евгений Степанищев (bolknote.ru) 2012

Комментарий для razetdinov.ya.ru:

Похоже, ты пропустил недавнюю JS-драму с участием мэтров яваскрипта: http://jsdrama.com/

Да я как-то не слежу :) Почитаю, спасибо!

Евгений Степанищев (bolknote.ru) 2012

Комментарий для fulc.ru:

Вот тут еще несколько граблей, на которые можно наступить, если не ставить точки с запятой: http://lucumr.pocoo.org/2011/2/6/automatic-semicolon-insertion/

Тысячи их. Смысл не в том, чтобы не ставить точку с запятой и этим экономить байт, а в том, чтобы предотвращать появление ошибки такой простой штукой. Это как в Си рекомендуется в сравнении ставить константу слева, чтобы найти ошибку сразу, если вдруг забудешь одно «равно» поставить.

maxim-zotov 2012

Комментарий для Евгения Степанищева:

Это как в Си рекомендуется в сравнении ставить константу слева

Это дурацкая рекомендация, выворачивающая мозг. «Если 5 равно длине» — совершенный дурдом. Когда комфортная читаемость кода приносится в жертву надуманной проблеме — это зло. А надуманная потому, что на выражение «if (i=5)» компилятор (например, gcc) выдает предупреждение. Да даже если бы и не выдавал, так всё равно писать нельзя. Код должен быть логичным. В нем должно быть ясно видно то, что он делает, и чтобы его можно было читать гладко, а не спотыкаясь.

И в самом посте тоже извращения. Сэкономили один байт, поставив семантически бессмысленнейшую конструкцию. !function. Что и зачем здесь отрицается? Это форма без содержания. Это от мизантропии? «Да чтоб у вас крышу сорвало, если надумаете читать моё произведение!»

Особый шик ситуации в том, что это уродование кода оправдывается тем, что оно как бы решает другую проблему кода: отсутствие знаков препинания. «Я накосячил, забив на точки с запятой, но это может вызвать проблемы, поэтому нужно накосячить еще больше — ставить восклицательные знаки там, где они вообще не уперлись.»

maxim-zotov 2012

А, еще по теме: изоляция с помощью фиктивной функции — тоже тот еще праздник читаемости. Но это уже косяк языка, тут уж ничего не поделаешь, тут действительно приходится писать нелепые конструкции.

zg (zg.livejournal.com) 2012

Комментарий для maxim-zotov:

«Если 5 равно длине» — совершенный дурдом.

почему?

maxim-zotov 2012

Комментарий для zg.livejournal.com:

Я просто теряюсь, что тут требуется какое-то объяснение. Потому что 5 не может быть чему-то равно или не равно, оно 5 и есть, это уже значение, свойство, оно не может изменяться. Постановка вопроса «чему равно 5?» бессмысленна по сути. Это у объекта может быть какое-то свойство, у свойства не может быть объекта.

someone 2012

Комментарий для maxim-zotov:

Согласен с вами, очень разумно всё говорите.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для maxim-zotov:

Это дурацкая рекомендация, выворачивающая мозг. «Если 5 равно длине» — совершенный дурдом.

Вы уж ерунды-то не говорите. Если вы так читаете это конструкцию, то вы делаете ошибку. Она означает «если пять и длина равны между собой». Тем более, что в ПХП и многих других языках с автоматическим приведением типов она работает именно так.

И в самом посте тоже извращения. Сэкономили один байт, поставив семантически бессмысленнейшую конструкцию. !function. Что и зачем здесь отрицается? Это форма без содержания. Это от мизантропии? «Да чтоб у вас крышу сорвало, если надумаете читать моё произведение!»

А оборачивание скобками — форма с содержанием что ли? Пока не ввели «let» приходится изолировать функцией-выражением, выражение можно строить любым способом. Не нравится вам восклицательный знак, используйте тильду что ли.

Код должен быть логичным. В нем должно быть ясно видно то, что он делает, и чтобы его можно было читать гладко, а не спотыкаясь.

Код должен быть читаемым, а программист должен хорошо знать язык и основные его «хаки».

Yehat 2012

Сделаем жабаскрипт гибким, как зарытый в землю Перл.

Yehat 2012

Возможно, кто-то помнит эту шутку: мол, Перл гибок, как зарытый в землю шланг. Тут примерно та же фигня: красявость в ущерб читаемости. Я тоже люблю так писать, если не думаю о тех, кто будет разбираться в моём коде.

maxim-zotov 2012

Комментарий для Евгения Степанищева:

А оборачивание скобками — форма с содержанием что ли?

У скобок только структурирующая функция, поэтому они смотрятся не так дико. Они не выполняют никакого модифицирующего действия. Тильда или восклицательный знак — абсолютно без разницы, какое именно бессмысленное отрицание применяется к выражению.

twitter.com/thenameisbusy 2012

Комментарий для Евгения Степанищева:

Евгений, я думаю, что следует дополнить, может для кого и не очевидно, что такая функция будет возвращать только приведенное к булеву типу (и инвертированное) значение.

Т. е. в данном случае (из пустой функции), просто вернется «!undefined», т. е. true :-).

Евгений Степанищев (bolknote.ru) 2012

Комментарий для maxim-zotov:

У скобок только структурирующая функция, поэтому они смотрятся не так дико. Они не выполняют никакого модифицирующего действия.

Выполняют, конечно. Они переключают контекст. Если вы имеете ввиду, что скобки смотрятся более логично, возможно, но только профессионалу должно быть всё равно, что переключает контекст, а новичку непонятны оба выражения.

Но я за то выражение, которое страхует от такой частой ошибки как отсутствующая точка с запятой.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для Yehat:

Сделаем жабаскрипт гибким, как зарытый в землю Перл.

Если вы хоть что-то знаете о прогрессе стандарта, то видите, наверное, что он становится похожим скорее на Пайтон, а не на Перл.

sergey.larionov (openid-provider.appspot.com/sergey.larionov) 2012

Есть так называемые общепринятые практики, в качестве которых в джаваскрипте могут выступать и такие хаки. Тут же всё дело в том, что стандарт изменить непросто и нужно пользоваться тем, что есть.
Опытный разработчик на таких вещах не спотыкается, он видит за ним смысл. Просто найдите какой-нибудь js-код начала 2000-х и почитайте — сейчас пишут гораздо понятнее, как раз благодаря такой стандартизации со стороны самих программистов.

Кстати,сейчас мир js разбился на два лагеря — сторонники точек с запятыми и противники. В зависимости от того, кто из них победит и будет в дальнейшем определяться стандарт языка.
Противникам точек с запятыми приходится, кстати использовать особенности языка и различные хаки, чтобы у них всё работало и не слипалось при минимизации, а сторонникам приходится ставить много точек с запятыми :)

Евгений Степанищев (bolknote.ru) 2012

Комментарий для openid-provider.appspot.com/sergey.larionov:

Кстати,сейчас мир js разбился на два лагеря — сторонники точек с запятыми и противники.

Я — «за», кстати, за точки с запятой.

alax.myopenid.org 2012

Комментарий для maxim-zotov:

Это дурацкая рекомендация, выворачивающая мозг. «Если 5 равно длине» — совершенный дурдом.

Я, конечно, могу понять для чего это делается — чтобы случайно пропустив знак равенства нарваться на ошибку компилятора, но даже при этом я в этом вопросе разделяю твой взгляд. Всегда когда встречаю «if(константа = переменная» возникает небольшое чувство отвращения. Всегда ведь логически — по той логике по которой работает мозг — последующее исполнение зависит именно от значения переменной, поэтому с неё было бы логично и начать.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для alax.myopenid.org:

Да, я мне и самому не нравится. Но так безопаснее.

SiMM 2012

Комментарий для Евгения Степанищева:

Опять офф:

Офф: почему если я нажимаю ← старее http://bolknote.ru/write/236/ я имею в итоге всего две статьи?

Либо так, либо две статьи будут на последней странице.

Последнее мне кажется логичнее.

PS: почему я не могу ответить лично автору? ;) В списке значатся варианты «всем» и трое отписавшихся.

А зачем? Я и так всё читаю.

А сейчас — могу (ибо автор есть в числе отписавшихся, полагаю). Это не для автора, это для других ;)

Евгений Степанищев (bolknote.ru) 2012

Комментарий для SiMM:

Последнее мне кажется логичнее.

Совершенно не логичнее. Большинство читают последнюю страницу, им гораздо удобнее ничего не листать.

А сейчас — могу (ибо автор есть в числе отписавшихся, полагаю). Это не для автора, это для других ;)

Я подумаю на эту тему :)

SiMM 2012

Комментарий для Евгения Степанищева:

Большинство читают последнюю страницу

Есть статистика? Не знаю, как большинство (нет статистики), но я чаще перелистываю назад, а уж до последней страницы времён динозавров доберусь врядли.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для SiMM:

Есть.