Современный фронтенд несётся скоростным поездом, в окнах мелькают es6, es7 es2015, react, redux и куча других пассажиров. И не везде этот поезд останавливается. Но на станциях по-прежнему полно …jQuery.
И сегодня понадобилось дополнить “чужой” обработчик события (для простоты пусть будет onClick) дополнительными проверками, которые “чужим” не предусмотрен:
jQuery('element').bind('click', function() { if (checkIt()) { doIt(); } });
В дополнение к checkIt() необходимо позвать ещё и testIt().
В простейшем случае обработчик события может быть именованной функцией и задача становится тривиальной:
// editable "original" function clickHandler(event) { if (checkIt()) { doIt(); } } jQuery('element').bind('click', clickHandler); // custom code jQuery('element').unbind('click').bind(function(e) { if (testIt()) { clickHandler(e); } });
Но “чужой” код изменить нельзя, а значит обработчик события останется анонимной функцией. Как до неё добраться ?
Беглый поиск по исходникам jQuery помог найти недокументированный метод jQuery._data, который поможет добраться до скрытых в его недрах обработчиков события. Несмотря на наличие комментария:
_Never_ expose “private” data to user code (TODO: Drop _data, _removeData)
в интересующей меня ветке 1.xx, методы (вместе с комментарием) перекочевали в последнюю на данный момент версию 3.1, а значит я без риска и страха использую их и даже порекомендую вам сделать тоже самое, но всё же на ваш страх и риск, в похожей небезвыходной ситуации.
И так к делу:
// original HARDcode jQuery('element').bind('click', function() { if (checkIt()) { doIt(); } }); // custom code var originalClickHandler = jQuery._data( element ).events.click[0].handler; // save handler jQuery('element') .unbind('click') // remove handler .bind('click', function(e) { if (testIt()) { // wrap old handler with custom logic originalClickHandler(e) } });
Буду надеятся что таким чудо{вищным} методом никому больше воспользоваться не придётся.