addEventListener используя apply () - PullRequest
2 голосов
/ 23 мая 2010

Я пытаюсь вызвать addEventListener () с помощью метода apply (). Код похож на:

function rewrite(old){
    return function(){
        console.log( 'add something to ' + old.name );
        old.apply(this, arguments);
    }
} 
addEventListener=rewrite(addEventListener);

Это не работает. Код работает для обычного метода JavaScript, например,

function hello_1(){
    console.log("hello world 1!");
}
hello_1=rewrite(hello_1);

Нужна помощь!

Спасибо!

1 Ответ

9 голосов
/ 23 мая 2010

К сожалению, вы не можете рассчитывать на то, что addEventListener будет настоящей функцией Javascript. (Это верно для некоторых других функций, предоставляемых хостом, например window.alert). Многие браузеры делают правильную вещь (tm) и делают их истинными функциями Javascript, но некоторые браузеры этого не делают (я смотрю на вас, Microsoft). И если это не настоящая функция Javascript, у нее не будет функций apply и call в качестве свойств.

Следовательно, вы не можете сделать это в общем случае с помощью функций, предоставляемых хостом, потому что вам нужна функция apply, если вы хотите передать произвольное количество аргументов от вашего прокси к вашей цели. Вместо этого вы должны использовать специальные функции для создания оболочек, которые знают сигнатуру задействованной функции хоста, например:

// Returns a function that will hook up an event handler to the given
// element.
function proxyAEL(element) {
    return function(eventName, handler, phase) {
        // This works because this anonymous function is a closure,
        // "closing over" the `element` argument
        element.addEventListener(eventName, handler, phase);
    }
}

Когда вы вызываете это, передавая элемент, он возвращает функцию, которая подключит обработчики событий к этому элементу через addEventListener. (Обратите внимание, что IE до IE8 не имеет addEventListener, хотя; вместо этого он использует attachEvent.)

Не знаю, подходит ли это вашему варианту использования или нет (в противном случае более подробная информация о сценарии использования будет полезна).

Вы бы использовали выше, как это:

// Get a proxy for the addEventListener function on btnGo
var proxy = proxyAEL(document.getElementById('btnGo'));

// Use it to hook the click event
proxy('click', go, false);

Обратите внимание, что мы не передавали ссылку на элемент в proxy, когда вызывали его; это уже встроено в функцию, потому что функция является замыканием. Если вы не знакомы с ними, моя запись в блоге Закрытия не сложны могут быть полезны.

Вот полный пример:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Test Page</title>
<style type='text/css'>
body {
    font-family: sans-serif;
}
#log p {
    margin:     0;
    padding:    0;
}
</style>
<script type='text/javascript'>

    window.onload = pageInit;
    function pageInit() {
        var proxy;

        // Get a proxy for the addEventListener function on btnGo
        proxy = proxyAEL(document.getElementById('btnGo'));

        // Use it to hook the click event
        proxy('click', go, false);
    }

    // Returns a function that will hook up an event handler to the given
    // element.
    function proxyAEL(element) {
        return function(eventName, handler, phase) {
            // This works because this anonymous function is a closure,
            // "closing over" the `element` argument
            element.addEventListener(eventName, handler, phase);
        }
    }

    function go() {
        log('btnGo was clicked!');
    }

    function log(msg) {
        var p = document.createElement('p');
        p.innerHTML = msg;
        document.getElementById('log').appendChild(p);
    }

</script>
</head>
<body><div>
<input type='button' id='btnGo' value='Go'>
<hr>
<div id='log'></div>
</div></body>
</html>

Относительно вашего вопроса ниже относительно func.apply() против func(), я думаю, вы, вероятно, уже поняли это, просто мой первоначальный неправильный ответ запутал вопросы. Но на всякий случай: apply вызывает функцию, делая две особые вещи:

  1. Устанавливает, что this будет в вызове функции.
  2. Принимает аргументы, переданные функции в виде массива (или любой подобной массиву вещи).

Как вы, наверное, знаете, this в Javascript сильно отличается от this в некоторых других языках, таких как C ++, Java или C #. this в Javascript не имеет ничего общего с тем, где определена функция, она полностью определяется тем, как функция называется . Вы должны установить this на правильное значение каждый раз, когда вызываете функцию. (Подробнее о this в Javascript здесь .) Есть два способа сделать это:

  • путем вызова функции через свойство объекта; который устанавливает this для объекта в вызове. например, foo.bar() устанавливает this на foo и вызывает bar.
  • Вызывая функцию через ее собственные свойства apply или call; те установили this на первый аргумент. Например, bar.apply(foo) или bar.call(foo) установит this в foo и вызовет bar.

Единственное различие между apply и call заключается в том, как они принимают аргументы для передачи целевой функции: apply принимает их как массив (или что-то вроде массива):

bar.apply(foo, [1, 2, 3]);

, тогда как call принимает их как отдельные аргументы:

bar.apply(foo, 1, 2, 3);

Оба они вызывают bar, устанавливая this в foo и передавая аргументы 1, 2 и 3.

...