Поздняя инициализация - альтернатива Observer`у

Часто при создании страниц является проблемой наличие единственного и неповторимого события window.onload (оно же может задаваться в теге "BODY" через св-во "onLoad"), ибо различные сценарии используют его для своей инициализации и им порой бывает трудно договориться о едином механизме включения своих блоков в функцию, служащую обработчиком этого события, что бы все они в итоге корректно были проинициализированы.Обычно в качестве вспомогательного механизма для разруливания таких конфликтов используется Pattern "Observer". Его суть в том, что заводится специальный реестр, к которому специальным методом осуществляется обращение по добавлению слушателя на событие полной загрузки страницы, который предполагает, что кроме него никто не воспользуется событием window.onload.Однако на практике я часто сталкивался с ситуациями, когда один и тот же сценарий используется в разных страницах с разными механизмами реализации этого шаблона, а где-то не используется вообще. Плюс к этому есть весьма сложные скрипты, которые нельзя трогать и выискивать в них обращение к window.onload дело весьма неблагодарное - так происходит, когда над одной и той же страницей работает десяток человек. В таких ситуациях оказывается наиболее оптимально просто навесить поверх всех существующих ещё один блокинициализации, не трогая всех остальных, оставив остальным инициализироваться как они хотят - хоть путём прямой перезаписи window.onload, хоть обсерверами.Так что для таких ситуаций я писал следующий сценарий:
/** @param {function} Init + */addOnLoadListener = function(Init) {    var /** @type {function} */ pastInitFn = window.onload;    if (pastInitFn)        window.onload = function() { pastInitFn(); Init(); }    else        window.onload = Init;    };//Предположим, кто-то "грязно" вмешался и перепрописал механизм инициализации, затерев всё, что, возможно, было там до него. Мы не хотим вмешиваться так же - просто хотим добавить к этой свою функциональность.window.onload = function(){alert(1);};//...(function() {    function Init() {                alert(2);        //...    }    window.addOnLoadListener(Init);})();//...window.addOnLoadListener(function() {            alert(3);    //...});    })();
Вот так вот аккуратненько можно решить эту проблему, не трогая существующий код инициализации. Конечно, это не спасёт нас, если кто-то ПОСЛЕ исполнения нашего кода "грязно" перепишет window.onload - но это уже будет виной того, кто это сделает, защититься от этого уже не представляется возможным.
10 ответов

А разве добавление обработчиков через addEventListener не спасает от всех проблем?


А разве добавление обработчиков через addEventListener не спасает от всех проблем? 
Вы про этот? Спасал бы, если бы был реализован в IE, но им он не поддерживается.Впрочем, можно написать библиотечку, которая бы как раз реализовывала на JS нормальную функциональность этого метода в Mozilla`е. Но это довольно большая работа - писать, тестировать...


attachEvent


attachEvent 
С ним проблема обратная - он не является частью стандарта и поддерживается только Internet Explorer`ом.В принципе, можно было бы реализовать эту задачу как переходник - сначала действовать по стандарту, а в случае ошибки - вызывать attachEvent... Можно так 


Се ля ви, функция универсального навешивания события написана 100 лет назад и не разу никого не подводила. Если не ошибаюсь, один из вариантов есть в закрепленной теме "все про события". Один из вариантов:
function attachEventListener(target, eventType, functionRef,    capture) {  if (typeof target.addEventListener != "undefined")  {    target.addEventListener(eventType, functionRef, capture);  }  else if (typeof target.attachEvent != "undefined")  {    target.attachEvent("on" + eventType, functionRef);  }  else  {    eventType = "on" + eventType;    if (typeof target[eventType] == "function")    {      var oldListener = target[eventType];      target[eventType] = function()      {        oldListener();        return functionRef();      };    }    else    {      target[eventType] = functionRef;    }  } }
Здается мне надежней/правильней таки использовать такую функцию чем ваш подход.


В базе знаний XPoint'а раньше тоже висел подобный пример, но пару лет назад третью ветку из него решили выкинуть - браузеров, понимающих JS, но не понимающих ни attachEvent, ни addEventListener, в реальном мире практически не осталось...


solenko, неплохо, но нельзя ли это как-то присобачить ко всем элементам? Что бы по сути просто сделать заплатку для браузеров, понимающих лишь "attachEvent", что бы заставить их работать по стандарту?Попытался добавить к Node - оказалось, что в FF это просто кучка констант, а IE вообще такого не знает... :(


К сожалению, в IE, насколько мне известно, элементы не являются "тру-объектами" и расширить их через базовый прототип HTMLElement'а (как в др. браузерах) не получится (хотя обходные решения попадаются, но, как правило, довольно некузявые). А вот сделать наоборот - расширить интерфейс HTMLElement'а в остальных браузерах "мелкомягкими" вариантами методов - достаточно легко (вот первый найденный в гугле вариант).


Да вы чё, парни!Люди уже давно пользуются кроссбраузерной реализацией обработчика события domContentLoaded, а вы тут обсуждаете onload и навешивание обработчиков!Хотя справедливости ради скажу, что я не спешу переходить на использование domContentLoaded, т.к. периодически замечаю глюки в ИЕ.


Avb, фишка для IE в scrollLeft. Глюков нет. А отсутствие прототипов для Node в IE, по моему мнению, не является страшным. Аля процедурное программирование в студию