РСС

Ношу шлем, тяжело дышу…

Меня зовут Антон Шувалов. Я работаю в Lazada. Кроме программирования я пишу музыку и иногда занимаюсь дизайном интерфейсов. Я есть в Twitter, Facebook, и на GitHub. Вы можете написать мне email.

Если вы задумали порадовать меня небольшим подарком (не может быть!) — вот список моих мещанских мечт.

ASI и мистические знаки перед IIFE в JavaScript

В JavaScript часто можно встретить такую констркуцию и различные вариации:

;(function($, undefined){ // my awesome code here })(jqery);

В числе странных мистических знаков перед IIFE могут встречаться, наверное, любые унарные операторы (~, ! или void) и точка с запятой. Впервые увидев в коде что-то в духе ~(function(){}()) можно и испугаться, но на самом деле причина прозаична.

ASI

В JavaScript есть механизм автоподстановки точек с запятой (ASI), позволяющий программистам не заботиться о том, чтобы в конце выражения всегда стояла ; — ASI самостоятельно разберется с тем, чтобы в конце каждой строки стоял необходимый символ. Но ASI срабатывает лишь в определенных случаях. Подробнее об этом можно прочитать в спецификации, я же процитирую только самое интересное:

Когда в ходе последовательного разбора текста программы слева направо встречается токен (называемый токеном-нарушителем), который не позволяется никаким из правил грамматики, то точка с запятой автоматически вставляется перед токеном-нарушителем, если выполняется одно из следующих условий:

  1. Токен-нарушитель отделён от предыдущего токена как минимум одним КонцомСтроки.
  2. Токеном-нарушителем является закрывающая фигурная скобка }.

ASI и мистические знаки перед IIFE в JavaScript

фото: RyanRWarner

Проще всего это объяснить на примере. И так, в первом случае ASI сработает, потому что функции foo не существует на уровне грамматики языка:

var a = b + c
foo(a)

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

// 1
var a = b + c
-a ? foo() : bar()

// 2
var a = b + c
(-a) ? foo() : bar()

// 3
var a = b + c
[a, b, c].map(alert)

В этих случая ASI не сработает, и JavaScript проинтерпретирует эти строки несколько иначе, чем мы было ожидали:

// 1
var a = b + c-a ? foo() : bar()

// 2
var a = b + c(-a) ? foo() : bar()

// 3
var a = b + c[a, b, c].map(alert)

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

Сборка JavaScript

На большинстве сайтов JavaScript собирается в один файл с помощью какой-то вариации на тему cat *.js > app.js, затем еще минифицируется, и, скорее всего, регулярными выражениями, потому что строить AST-дерево достаточно долго, и только затем уже записывается в известный каждому фронтент-разработчику файл app.min.js. Но вообще, все может не ограничиваться этим: разработчики могут, к примеру, решить, что нужно вырезать console.log на production-сборке, и, конечно, регулярными выражениями (Esprima, тебя не существует!).

Так вот, благодаря всему этому процессу, может легко получиться ситуация, в которой перед (function(){})() появится что-то, что помешает ASI сделать свою работу, и наградит вас потрясающим гейзенбагом, который будет пропадать, как только вы отключите процессинг JS. Конечно эта ошибка не такая уж и сложная, но не имея представления о ASI, IIFE и минификации, можно серьезно запутаться в происходящем.

По этому-то опытные разработчики ставят точку с запятой перед немедленно вызывающимися функциональными выражениями, предотвращая возможные баги во время сборки JavaScript.

ASI и мистические знаки перед IIFE в JavaScript

Подписывайтесь на РСС. Всем добра и приключений!

фото: hperticarati

«Как рушатся комплексные системы», Ричард И. Кук
О фундаментальных проблемах больших запутанных систем
7 паттернов для рефакторинга JavaScript-приложений
Перевод отличной серии статей о проектировании и рефакторинге проектов
Музыка для работы
Мои плейлисты: теплый glitch, нежные девичьи голоса, интересная электроника и chillwave
Ссылколог
Коллекционирую полезные ссылки