Кратко: BX.proxy
и BX.delegate
— это «фабрики» функций-делегатов, которые помогают корректно передавать контекст (this
) в обработчики событий, колбэки AJAX и другие асинхронные вызовы во фронтенде 1С-Битрикс.

Зачем нужны делегаты?
JavaScript теряет исходный this
, когда метод объекта передаётся как колбэк:
someBtn.onclick = obj.method; // внутри method «this» укажет на кнопку, а не на obj
Чтобы вернуть контексту правильное значение, Bitrix-ядро предоставляет две удобные оболочки:
BX.proxy(func, context); // кэширует делегат
BX.delegate(func, context); // создаёт новый делегат каждый раз
В чём разница между BX.proxy
и BX.delegate
?
Критерий | BX.proxy | BX.delegate |
---|---|---|
Кэширование результата | Да — при одинаковых аргументах возвращает ту же ссылку на функцию-делегат. | Нет — создаёт новый объект функции каждый вызов. |
Удобно снимать обработчики? | Да — можно «отвязать» именно тот обработчик, что был назначен. | Труднее — нужен доступ к той же самой ссылке, а делегат каждый раз новый. |
Аналог в jQuery | — | jQuery.proxy |
Минимальный пример
Разметка
<button id="show-title">Показать содержимое</button>
Скрипт
<script>
/**
* Класс-демонстратор.
*/
function Card(title) {
this.title = title;
BX.bind(
BX('show-title'),
'click',
// сохраняем контекст класса для обработчика
BX.proxy(this.handleClick, this)
);
}
Card.prototype.handleClick = function (e) {
alert(this.title); // корректно выводит заголовок
// снимаем обработчик, используя ту же ссылку-делегат
BX.unbind(
BX('show-title'),
'click',
BX.proxy(this.handleClick, this)
);
};
BX.ready(function () {
new Card('Моя первая карточка');
});
</script>
Если заменить BX.proxy
на BX.delegate
, то второй вызов создаст другую функцию, и BX.unbind
не найдёт нужный обработчик.
Проверка кэширования
function foo() {}
var ctx = { a: 1 };
console.log(
BX.proxy(foo, ctx) === BX.proxy(foo, ctx) // true
);
console.log(
BX.delegate(foo, ctx) === BX.delegate(foo, ctx) // false
);
Практический кейс: AJAX-запрос
/**
* Компонент, отправляющий AJAX и обрабатывающий ответ в своём контексте.
*/
class CommentsWidget {
constructor(url) {
this.endpoint = url;
}
refresh() {
BX.ajax.post(
this.endpoint,
{ sessid: BX.bitrix_sessid() },
// сохраняем «this» через делегат
BX.proxy(function (data) {
this.render(JSON.parse(data));
}, this)
);
}
render(comments) {
console.log('Получены комментарии', comments);
}
}
BX.ready(() => {
const widget = new CommentsWidget('/api/comments.php');
widget.refresh();
});
Передаём дополнительные аргументы
Иногда нужно «подмешать» параметры в делегат. Самый гибкий способ — анонимная обёртка:
BX.bind(
targetNode,
'click',
BX.proxy(function (event) {
this.process(event, 42, 'extra-data');
}, this)
);
Что делать не нужно
// Неправильно: handler(arg) вызывается немедленно!
BX.bind(targetNode, 'click', BX.proxy(this.handler(arg), this));
Альтернатива без Bitrix-функций — нативный Function.prototype.bind
, но он не кэширует результат, поэтому для последующего BX.unbind
придётся хранить ссылку на делегат вручную:
this._clickDelegate = this.handler.bind(this, arg);
BX.bind(targetNode, 'click', this._clickDelegate);
// ...
BX.unbind(targetNode, 'click', this._clickDelegate);
Под капотом: как это работает?
- Создание делегата
Оба метода возвращают новую функцию (wrapper
), внутри которой вызываетсяfunc.apply(context, arguments)
. - Кэширование (только
BX.proxy
)
Bitrix хранит ассоциативный массив__bx_proxy_cache
(или похожий), где ключом служит строчкаfunc + '_' + context
. Если такой ключ уже есть, возвращается сохранённыйwrapper
. - Удаление обработчика
Благодаря одинаковой ссылке,BX.unbind
легко находит именно тотwrapper
, который был повешен ранее.
Советы по использованию
- Для большинства сценариев выбирайте
BX.proxy
— он помогает и добавить, и потом убрать обработчик. BX.delegate
подходит, если гарантированно не придётся откреплять обработчик или нужно всегда получать свежий делегат (редкий случай).- Храните делегаты, если снимаете события часто. При большом числе динамически создаваемых элементов можно сохранить ссылку в свойстве объекта или
data-*
атрибуте узла. - Не злоупотребляйте передачей анонимных функций внутрь
BX.proxy
. Если обёртка логически отделима, вынесите её в метод класса — это облегчит отладку и переиспользование.
Итог
BX.proxy
и BX.delegate
— незаменимые инструменты при работе с событиями и асинхронными вызовами в 1С-Битрикс. Зная их различия и правильно управляя контекстом, вы избежите типичной ошибки «потерянного this» и сделаете код обработчиков чище, надёжнее и легче для поддержки.