Function hoisting
Mar. 22nd, 2013 03:59 am![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Блин, какой сюрприз неприятный. Оказывается SpiderMonkey – это движок javascript в FireFox – не поддерживает hoisting в блоках.
Такой код выполнится верно везде, кроме FF:
if (true) { f1(); function f1 (){console.log("f1 called")} }
В ff оно выбросит ошибку. Это феерическое блядство, потому что толкование стандарта, причём поперёк устоявшейся традиции – это очень грустно. Заметим, что код, не включенный в блок if, отработает верно и в FF. Это, например, так (здесь я создаю анонимную функцию и сразу её вызываю, код исполняется в lexical scope этой анонимной функции, а не в блоке):
if (true) { (function(){ f1(); function f1 (){console.log("f1 called")} })(); }
Это типичный пример применения стандарта по-максимуму в нестрогом режиме по самой лучшей на свете причине – “потому что гладиолус”. В строгом режиме такое поведение вполне ок, а в обычном такой запрет сразу затрудняет очень удобную, простую и визуально понятную схему записи цепочек-деревьев асинхронных вызовов:
function loadSomething (key) { if (key) { load ({url:"index", complete:indexLoaded}); function indexLoaded (data) { ...filter keys... load ({url:"content", keys:[...], complete:contentLoaded }); } function contentLoaded (data) { ...analyze & render content... load ({url:"aux", keys:[...], complete:auxLoaded}); } function auxLoaded (data) { ...so on... } } else { ...get something else... } }
Это работает везде, кроме FF. В FF это тоже заработает, если внутрь каждого блока if затолкать замыкание, которым обернуть цепочку.
Это нам сразу даёт создание нового контекста (затраты памяти ненужные, утечка по сути – это замыкание хрен когда будет прибито сборщиком мусора), дополнительное время на связывание с переменными внешнего для замыкания контекста (это lexical scope вызывающей функции).
Короче, огнелис перехитрил сам себя. Как это обычно и бывает в случаях дурацких запретов.
Ну и конечно подогнал геморроя на ровном месте, нипочему.