Под впечатлением от
этой и
этой статей обновил декоратор.
Раньше он позволял только выполнить функцию перед или после другой функцией. Новая, расширенная версия, хоть и наложила ограничения на функции-обертки, имеет больше возможностей:
- подмена передаваемых аргументов;
- отмена выполнения;
- подмена возвращаемого значения.
Сам код, собственно (на
github):
function decorate (initial, decorate_before, decorate_after) {
return function () {
var initial_call_result,
updated_params,
updated_result;
if (typeof decorate_before === 'function') {
updated_params = decorate_before.apply(this, arguments);
if (!updated_params) {
return;
}
}
initial_call_result = initial.apply(this, updated_params || arguments);
if (typeof decorate_after === 'function') {
updated_result = decorate_after.apply(this, arguments);
}
return updated_result || initial_call_result;
};
}
Из изменений: результат первой функции оберки используется как аргументы для вызова оригинальной функции.
Значит можно явно создавать свои варианты биндинга для функций. Например, чтобы при работе с jquery не указывать каждый раз контекст, можно создать обертку, в которой контекст явно задан:
var $iframe;
var iframe_context = $('iframe').eq(0);
$iframe = decorate($, function (selector, context) {
return [selector, iframe_context];
});
// вместо явного указания:
var images = $('img', iframe_context);
// используем обертку
var images = $iframe('img');
Когда первая обертка не возвращает массив, считается, что оригинальную функцию не надо вызывать. Такой подход можно применять, когда надо подправить поведение плагина, но не хочется влезать в тонкости его реализации. При обновлении плагина не надо будет снова тормошить его внутренности в поисках изменений, так как код реализации и код допиливания будет разделен.
К тому-же некоторые баннерные сети до сих пор используют document.write для вставки ского кода. Если появляется желание обхитрить сеть и вставить их код асинхронно, то реализовать желание можно с помощью переписывания document.write.
// отмена поведения метода плагина
plugin.method = decorate(plugin.method, function () {
if (!ok_flag) {
return;
} else {
return arguments;
}
});
// вставка кода рекламного блока в обход document.write
document.write = decorate(document.write, function () {
if (is_advert(arguments)) {
on_advert_embeding.apply(this, arguments);
} else {
return arguments;
}
});
Результат работы удобно подменять удобно при отладке кода. Когда часть системы уже готова, и известно как будет работать работать вторая часть, можно эмулировать ее поведение, подменой результатов ответа. Или же для юнит-тестирования частей системы.
get_products = decorate(get_products, function () {
if (debug) {
return;
}
}, function () {
if (debug) {
return ['1111', '2222', '3333', '4444'];
}
});