Function hoisting
Mar. 22nd, 2013 03:59 amБлин, какой сюрприз неприятный. Оказывается 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 вызывающей функции).
Короче, огнелис перехитрил сам себя. Как это обычно и бывает в случаях дурацких запретов.
Ну и конечно подогнал геморроя на ровном месте, нипочему.