Декларация-вызов в JS
Сегодня на первой части семинара Ильи Кантора по JS присутствовал (к сожалению, на второй части не получится, буду в Москве это время). Немного поговорили о частом паттерне «объявили функцию и тут же вызвали». Используется этот приём (если кто не знаком с ДжаваСкриптом) для изоляции — в этом языке функции единственное, что может создавать зоны видимости.
Я вскользь затронул свой любимый способ — описание функции и вызов через восклицательный знак или тильду, вместо оборачивания скобками. Вообще, в JS непосредственный вызов функции сразу по месту определения возможен, только если декларация находится в контексте выражения. Для этого и нужны традиционные скобки:
(function () {
// скобки вокруг функции говорят интерпретатору, что это выражение
})();
Вообще говоря, можно использовать любые средства, чтобы декларация стала частью выражения. Например, можно что-то прибавить к декларации. Или использовать любую унарную операцию.
Использование тильды или восклицательного знака гораздо лучше скобок по трём причинам:
!function () {
//
}();
Во-первых, на один байт меньше. Если таких функций много, экономия существенная. Во-вторых, скобки надо балансировать, а унарный оператор — нет.
И, в-третьих, самая главная причина. Вот такой код вызовет ошибку:
var a = 5
(function() {})()
Причём ошибку, которую найти иногда довольно трудно, да и сообщение о ней не самое дружественное: «TypeError: 5 is not a function». На самом деле, тут пропущена точка с запятой. Интерпретатор считает, что ему встретились две части выражения, между которыми пропущен какой-то знак. Эта ситуация часто встречается при автоматическом объединении двух скриптов в один.
Обычно для этого добавляют точку с запятой сразу перед такими блоками.
Но если использовать унарный оператор, то этой проблемы просто нет (поэтому, на самом деле, мы экономим два байта, ещё и точка с запятой не обязательна):
var a = 5
!function () {}()
Тут интерпретатор, встретив унарный оператор, понимает, что предыдущее выражение закончилось и началась новая конструкция.
Да, недавно наткнулся на такую ошибку, искал довольно долго.
Но мне кажется использование таких приемов и не расставления точек с запятых противоречит общепринятым код стандартам. Разве нет?
А какой смысл не использовать точки с запятой, кроме какого-нибудь спортивного программирования, где нужно уложиться в килобайт кода? И можно ли заметить разницу в размере кода в реальных ситуациях при экономии байтов? Польза от какого-нибудь сжимателя js будет гораздо больше.
Вот тут еще несколько граблей, на которые можно наступить, если не ставить точки с запятой: http://lucumr.pocoo.org/2011/2/6/automatic-semicolon-insertion/
Где именно то экономите 2 байта? ) JS-движки загружают в память все сырцы?
Офф: почему если я нажимаю ← старее http://bolknote.ru/write/236/ я имею в итоге всего две статьи?
PS: почему я не могу ответить лично автору? ;) В списке значатся варианты «всем» и трое отписавшихся.
Может «может», а не «могут»? :-)
Похоже, ты пропустил недавнюю JS-драму с участием мэтров яваскрипта: http://jsdrama.com/
By the way
Ограничивать видимость можно еще такой модной штукой как let
https://developer.mozilla.org/en/New_in_JavaScript_1.7#let_statement
Комментарий для fulc.ru:
При аккуратном программировании лучше использовать точку с запятой. Жизнь сложнее. Иногда люди её пропускают.
Комментарий для Андрей:
В файле. Причём здесь JS-движки?
Комментарий для SiMM:
Либо так, либо две статьи будут на последней странице.
А зачем? Я и так всё читаю.
Комментарий для cssblast.ru:
Её всё равно что нет. Кроме FF кто её ещё поддерживает?
Комментарий для razetdinov.ya.ru:
Да я как-то не слежу :) Почитаю, спасибо!
Комментарий для fulc.ru:
Тысячи их. Смысл не в том, чтобы не ставить точку с запятой и этим экономить байт, а в том, чтобы предотвращать появление ошибки такой простой штукой. Это как в Си рекомендуется в сравнении ставить константу слева, чтобы найти ошибку сразу, если вдруг забудешь одно «равно» поставить.
Комментарий для Евгения Степанищева:
Это дурацкая рекомендация, выворачивающая мозг. «Если 5 равно длине» — совершенный дурдом. Когда комфортная читаемость кода приносится в жертву надуманной проблеме — это зло. А надуманная потому, что на выражение «if (i=5)» компилятор (например, gcc) выдает предупреждение. Да даже если бы и не выдавал, так всё равно писать нельзя. Код должен быть логичным. В нем должно быть ясно видно то, что он делает, и чтобы его можно было читать гладко, а не спотыкаясь.
И в самом посте тоже извращения. Сэкономили один байт, поставив семантически бессмысленнейшую конструкцию. !function. Что и зачем здесь отрицается? Это форма без содержания. Это от мизантропии? «Да чтоб у вас крышу сорвало, если надумаете читать моё произведение!»
Особый шик ситуации в том, что это уродование кода оправдывается тем, что оно как бы решает другую проблему кода: отсутствие знаков препинания. «Я накосячил, забив на точки с запятой, но это может вызвать проблемы, поэтому нужно накосячить еще больше — ставить восклицательные знаки там, где они вообще не уперлись.»
А, еще по теме: изоляция с помощью фиктивной функции — тоже тот еще праздник читаемости. Но это уже косяк языка, тут уж ничего не поделаешь, тут действительно приходится писать нелепые конструкции.
Комментарий для maxim-zotov:
почему?
Комментарий для zg.livejournal.com:
Я просто теряюсь, что тут требуется какое-то объяснение. Потому что 5 не может быть чему-то равно или не равно, оно 5 и есть, это уже значение, свойство, оно не может изменяться. Постановка вопроса «чему равно 5?» бессмысленна по сути. Это у объекта может быть какое-то свойство, у свойства не может быть объекта.
Комментарий для maxim-zotov:
Согласен с вами, очень разумно всё говорите.
Комментарий для maxim-zotov:
Вы уж ерунды-то не говорите. Если вы так читаете это конструкцию, то вы делаете ошибку. Она означает «если пять и длина равны между собой». Тем более, что в ПХП и многих других языках с автоматическим приведением типов она работает именно так.
А оборачивание скобками — форма с содержанием что ли? Пока не ввели «let» приходится изолировать функцией-выражением, выражение можно строить любым способом. Не нравится вам восклицательный знак, используйте тильду что ли.
Код должен быть читаемым, а программист должен хорошо знать язык и основные его «хаки».
Сделаем жабаскрипт гибким, как зарытый в землю Перл.
Возможно, кто-то помнит эту шутку: мол, Перл гибок, как зарытый в землю шланг. Тут примерно та же фигня: красявость в ущерб читаемости. Я тоже люблю так писать, если не думаю о тех, кто будет разбираться в моём коде.
Комментарий для Евгения Степанищева:
У скобок только структурирующая функция, поэтому они смотрятся не так дико. Они не выполняют никакого модифицирующего действия. Тильда или восклицательный знак — абсолютно без разницы, какое именно бессмысленное отрицание применяется к выражению.
Комментарий для Евгения Степанищева:
Евгений, я думаю, что следует дополнить, может для кого и не очевидно, что такая функция будет возвращать только приведенное к булеву типу (и инвертированное) значение.
Т. е. в данном случае (из пустой функции), просто вернется «!undefined», т. е. true :-).
Комментарий для maxim-zotov:
Выполняют, конечно. Они переключают контекст. Если вы имеете ввиду, что скобки смотрятся более логично, возможно, но только профессионалу должно быть всё равно, что переключает контекст, а новичку непонятны оба выражения.
Но я за то выражение, которое страхует от такой частой ошибки как отсутствующая точка с запятой.
Комментарий для Yehat:
Если вы хоть что-то знаете о прогрессе стандарта, то видите, наверное, что он становится похожим скорее на Пайтон, а не на Перл.
Есть так называемые общепринятые практики, в качестве которых в джаваскрипте могут выступать и такие хаки. Тут же всё дело в том, что стандарт изменить непросто и нужно пользоваться тем, что есть.
Опытный разработчик на таких вещах не спотыкается, он видит за ним смысл. Просто найдите какой-нибудь js-код начала 2000-х и почитайте — сейчас пишут гораздо понятнее, как раз благодаря такой стандартизации со стороны самих программистов.
Кстати,сейчас мир js разбился на два лагеря — сторонники точек с запятыми и противники. В зависимости от того, кто из них победит и будет в дальнейшем определяться стандарт языка.
Противникам точек с запятыми приходится, кстати использовать особенности языка и различные хаки, чтобы у них всё работало и не слипалось при минимизации, а сторонникам приходится ставить много точек с запятыми :)
Комментарий для openid-provider.appspot.com/sergey.larionov:
Я — «за», кстати, за точки с запятой.
Комментарий для maxim-zotov:
Я, конечно, могу понять для чего это делается — чтобы случайно пропустив знак равенства нарваться на ошибку компилятора, но даже при этом я в этом вопросе разделяю твой взгляд. Всегда когда встречаю «if(константа = переменная» возникает небольшое чувство отвращения. Всегда ведь логически — по той логике по которой работает мозг — последующее исполнение зависит именно от значения переменной, поэтому с неё было бы логично и начать.
Комментарий для alax.myopenid.org:
Да, я мне и самому не нравится. Но так безопаснее.
Комментарий для Евгения Степанищева:
Опять офф:
Последнее мне кажется логичнее.
А сейчас — могу (ибо автор есть в числе отписавшихся, полагаю). Это не для автора, это для других ;)
Комментарий для SiMM:
Совершенно не логичнее. Большинство читают последнюю страницу, им гораздо удобнее ничего не листать.
Я подумаю на эту тему :)
Комментарий для Евгения Степанищева:
Есть статистика? Не знаю, как большинство (нет статистики), но я чаще перелистываю назад, а уж до последней страницы времён динозавров доберусь врядли.
Комментарий для SiMM:
Есть.