Есть ли какой-нибудь способ предотвратить изменение "этого", когда я завершаю функцию?

StackOverflow https://stackoverflow.com/questions/400968

  •  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.Честно говоря, я бы рекомендовал использовать фреймворк.Любой из них должен сделать обработку событий намного приятнее, чем делать это вручную.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top