Есть ли какой-нибудь способ предотвратить изменение "этого", когда я завершаю функцию?
-
03-07-2019 - |
Вопрос
Я хочу, чтобы все кнопки выполняли действие до и после своего обычного события onclick.Итак, мне пришла в голову "блестящая" идея перебрать все эти элементы и создать функцию-оболочку.
Когда я тестировал это, казалось, что это работает довольно хорошо, но когда я интегрировал это в наше приложение, оно развалилось.Я проследил это вплоть до того, что значение "this" было изменено моей оболочкой.Пример кода иллюстрирует это;перед переносом обработчиков событий каждая кнопка отображает идентификатор кнопки при нажатии, но после переноса отображаемое имя в этом примере "не определено" или "Form1", если вы запускаете его из формы.
Кто-нибудь знает лучший способ сделать то же самое?Или хороший способ сохранить первоначально предназначенные значения "this"?
Как вы можете себе представить, я не хочу изменять какой-либо существующий код обработчика событий в целевых кнопках.
Заранее благодарю.
PS-Целевой браузер - IE6 и выше, функциональность кроссбраузерной программы не требуется
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<script language="javascript" type="text/javascript">
function btnWrap_onClick()
{
var btns = document.getElementsByTagName("button");
for( var i = 0; i < btns.length; i++)
{
var btn = btns[i];
// handle wrap button differerntly
if( "btnWrap" == btn.id)
{
btn.disabled = true;
continue; // skip this button
}
// wrap it
var originalEventHandler = btn.onclick;
btn.onclick = function()
{
alert("Starting event handler");
originalEventHandler();
alert("Finished event handler");
}
}
alert("Buttons wrapped successfully");
}
</script>
<body>
<p>
<button id="TestButton1" onclick="alert(this.id);">TestButton1</button>
<button id="TestButton2" onclick="alert(this.id);">TestButton2</button>
</p>
<button id="btnWrap" onclick="btnWrap_onClick();">Wrap Event Handlers</button>
</body>
</html>
Решение
Нравится Пол Диксон сказал, что ты мог бы использовать звонить но я предлагаю вам использовать применять вместо этого.
Однако причина, по которой я отвечаю, заключается в том, что я обнаружил тревожную ошибку: Фактически вы заменяете все свои обработчики событий обработчиком событий последней кнопки. Я не думаю, что ты этого хотел, не так ли?(Подсказка:Вы заменяете значение для originalEventHandler на каждой итерации)
В приведенном ниже коде вы найдете работающее кроссбраузерное решение:
function btnWrap_onClick()
{
var btns = document.getElementsByTagName("button");
for( var i = 0; i < btns.length; i++)
{
var btn = btns[i];
// handle wrap button differerntly
if( "btnWrap" == btn.id)
{
btn.disabled = true;
continue; // skip this button
}
// wrap it
var newOnClick = function()
{
alert("Starting event handler");
var src=arguments.callee;
src.original.apply(src.source,arguments);
alert("Finished event handler");
}
newOnClick.original = btn.onclick; // Save original onClick
newOnClick.source = btn; // Save source for "this"
btn.onclick = newOnClick; //Assign new handler
}
alert("Buttons wrapped successfully");
}
Сначала я создаю новую анонимную функцию и сохраняю ее в переменной Новый щелчок.Поскольку функция - это объект, я могу создавать свойства для объекта function, как и для любого другого объекта.Я использую это для создания свойства оригинал это исходный обработчик onclick, и Источник это исходный элемент, который будет это когда вызывается исходный обработчик.
Внутри анонимной функции мне нужно получить ссылку на функцию, чтобы иметь возможность получить значение свойств оригинал и Источник.Поскольку у анонимной функции нет имени, я использую use аргументы.вызываемый абонент (это поддерживается начиная с MSIE5.5), чтобы получить эту ссылку и сохранить ее в переменной src.
Затем я использую следующий метод применять чтобы выполнить исходный обработчик onclick. применять принимает два параметра:первым будет значение это, а второй - это массив аргументов. это должен быть элементом, к которому был прикреплен исходный обработчик onclick, и это значение было сохранено в Источник. аргументы является внутренним свойством всех функций и содержит все аргументы, с которыми была вызвана функция (обратите внимание, что у анонимной функции нет указанных параметров, но если она все равно вызывается с некоторыми параметрами, они будут найдены в аргументы собственность).
Причина, по которой я использую применять заключается в том, что я могу переслать все аргументы, с которыми была вызвана анонимная функция, и это делает эту функцию прозрачной и кроссбраузерной.(Microsoft поместила событие в window.event, но другие браузеры предоставляют его в первом параметре вызова обработчика)
Другие советы
Вы можете использовать звонить способ устранения привязки, например originalEventHandler.call(btn);
В качестве альтернативы, может помочь библиотека, подобная prototype, - ее привязать метод позволяет вам создать новую функцию, привязанную к указанному объекту, поэтому вы бы объявили originalEventHandler как var originalEventHandler = btn.onclick.bind(btn);
Наконец, хорошую справочную информацию по вопросам привязки смотрите также Выход из ситуаций привязки в JavaScript
Ваша проблема заключается в том, как работают замыкания в JavaScript.Честно говоря, я бы рекомендовал использовать фреймворк.Любой из них должен сделать обработку событий намного приятнее, чем делать это вручную.