Как передать аргументы функции прослушивателя addEventListener?

Ситуация в чем-то похожа -

var someVar = some_other_function();
someObj.addEventListener("click", function(){
    some_function(someVar);
}, false);

Проблема в том, что значение someVar не отображается внутри функции прослушивателя addEventListener, где оно, вероятно, обрабатывается как новая переменная.

Очень четкая статья по этому поводу: toddmotto.com/avoiding-anonymous-javascript-functions

Aurelio 28.05.2014 18:57

Не самый чистый способ, но работает. Обратите внимание, что если someVar может быть только цифрой или текстом: eval ('someObj.addEventListener ("щелчок", function () {some_funct‌ ion (' + someVar + ');}); ‌');

Ignas2526 27.06.2014 20:37

Только что возникла эта проблема сегодня - решение, приведенное здесь, правильное (у других решений есть проблемы, такие как проблема с петлей и т. д.) - stackoverflow.com/a/54731362/984471

Manohar Reddy Poreddy 20.10.2019 08:00
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
358
3
522 165
31
Перейти к ответу Данный вопрос помечен как решенный

Ответы 31

Ответ принят как подходящий

В написанном вами коде нет абсолютно ничего плохого. И some_function, и someVar должны быть доступны, если они были доступны в контексте, когда анонимный

function() { some_function(someVar); } 

был создан.

Убедитесь, что предупреждение дает вам значение, которое вы искали, убедитесь, что оно будет доступно в рамках анонимной функции (если у вас нет другого кода, который работает с той же переменной someVar рядом с вызовом addEventListener)

var someVar; 
someVar = some_other_function();
alert(someVar);
someObj.addEventListener("click", function(){
    some_function(someVar);
}, false);

Это не работает в цикле for. Я всегда получаю последнее значение, а не то, которое принадлежало этой итерации. Любое решение?

iMatoria 25.06.2011 21:19

Кто-нибудь знает, почему это не работает в цикле? В чем причина такого поведения?

Morfidon 15.05.2015 04:23

@Morfidon, потому что функция с глобальными переменными действует как закрытие в javascript, что означает, что они запоминают среду за пределами своей лексической области. Если вы просто создаете разные функции в одной среде, они будут ссылаться на одну и ту же среду.

bugwheels94 20.05.2015 18:58

@Morfidon: в цикле значение someVar - это не то значение, которое оно имело при добавлении слушателя, а значение, которое оно имеет при выполнении слушателя. Когда слушатель выполняется, цикл уже завершился, поэтому значением someVar будет значение, которое оно имело при завершении цикла.

www.admiraalit.nl 29.10.2015 19:45

Это неправильный ответ, потому что он не позволяет нам использовать функцию removeEventListener после.

user5260143 04.12.2016 15:52

@ ankitbug94 Как можно было поместить someVar в Lexical scope, чтобы текущее значение можно было использовать внутри события? jQuery решает проблему с помощью event.dataapi.jquery.com/event.data, но как это сделать без jQuery?

Luke T O'Brien 22.06.2017 12:10

@iMatoria Я только что обнаружил, что создание bound function с использованием метода .bind() решит проблему с циклами developer.mozilla.org/en/docs/Web/JavaScript/Reference/…

Luke T O'Brien 22.06.2017 12:46

@ LukeTO'Brien Извините за такую ​​задержку с ответом. Если вы все еще хотите знать, вы всегда можете использовать частичные функции с использованием каррирования, который создает и возвращает новую функцию с их собственной лексической областью видимости. Вы можете найти это чрезвычайно полезным stackoverflow.com/questions/750486/…

bugwheels94 29.06.2017 22:02

@Morfidon см. Мой ответ ниже о том, что работает с циклами.

Hello World 23.11.2017 13:22

@NeonWarge: Пожалуйста, сравните профили перед таким жестким советом. Если вы эксперт в области SEO, вы должны знать, что ссылки становятся мертвыми, и посторонний не контролирует это. Вежливым способом можно было сообщить о неработающей ссылке и / или предложить исправление.

iMatoria 22.04.2018 06:47

когда он входит в some_function, someVar может уже не иметь ничего, ссылающегося на себя, и уже был очищен в кадре стека вызовов.

ROROROOROROR 25.07.2018 07:54

Что, если слушатель зарегистрирован в функции mycustom, а обратный вызов должен повторно использовать некоторую переменную из функции mycustom ПЛЮС Я хочу сделать обратный вызов как глобальную функцию customHandler вместо функции анонимного обратного вызова? Как передать переменную из функции mycustom в глобальную функцию customHandler?

Jerry 12.01.2020 18:48

Значение someVar должно быть доступно только в контексте some_function(), а не от слушателя. Если вы хотите, чтобы это было внутри слушателя, вы должны сделать что-то вроде:

someObj.addEventListener("click",
                         function(){
                             var newVar = someVar;
                             some_function(someVar);
                         },
                         false);

и используйте вместо него newVar.

Другой способ - вернуть значение someVar из some_function() для дальнейшего использования в слушателе (как новая локальная переменная):

var someVar = some_function(someVar);

Вы можете добавлять и удалять прослушиватели событий с аргументами, объявив функцию как переменную.

myaudio.addEventListener('ended',funcName=function(){newSrc(myaudio)},false);

newSrc - это метод с параметром myaudio в качестве параметра funcName - это переменная имени функции

Вы можете удалить слушателя с помощью myaudio.removeEventListener('ended',func,false);

Также попробуйте эти (IE8 + Chrome. Я не знаю для FF):

function addEvent(obj, type, fn) {
    eval('obj.on'+type+'=fn');
}

function removeEvent(obj, type) {
    eval('obj.on'+type+'=null');
}

// Use :

function someFunction (someArg) {alert(someArg);}

var object=document.getElementById('somObject_id') ;
var someArg = "Hi there !";
var func=function(){someFunction (someArg)};

// mouseover is inactive
addEvent (object, 'mouseover', func);
// mouseover is now active
addEvent (object, 'mouseover');
// mouseover is inactive

Надеюсь, опечаток нет :-)

Насколько сложно было бы дать исчерпывающий ответ? Стоит ли мне тестировать это на FF? Ну, я не буду беспокоиться ...

StefanNch 30.05.2013 14:24

Использовать

   el.addEventListener('click',
    function(){
        // this will give you the id value 
        alert(this.id);    
    },
false);

И если вы хотите передать любое пользовательское значение в эту анонимную функцию, самый простой способ сделать это -

 // this will dynamically create property a property
 // you can create anything like el.<your  variable>
 el.myvalue = "hello world";
 el.addEventListener('click',
    function(){
        //this will show you the myvalue 
        alert(el.myvalue);
        // this will give you the id value 
        alert(this.id);    
    },
false);

Отлично работает в моем проекте. Надеюсь, это поможет

Да, определенно помогло, так как оно также сохранило ожидаемый объем в цикле for.

j4v1 25.03.2020 21:34

Почему бы просто не получить аргументы из целевого атрибута события?

Пример:

const someInput = document.querySelector('button');
someInput.addEventListener('click', myFunc, false);
someInput.myParam = 'This is my parameter';
function myFunc(evt)
{
  window.alert(evt.currentTarget.myParam);
}
<button class = "input">Show parameter</button>

Помните, что JavaScript - это язык, ориентированный на прототипы!

Это правильный ответ, потому что он позволяет использовать после функции removeEventListener.

user5260143 04.12.2016 15:52

Разве это не должно быть evt.currentTarget.myParam? Если внутри someInput есть другой элемент, evt.target может относиться к внутреннему элементу. (jsfiddle.net/qp5zguay/1)

Herbertusz 24.01.2017 22:58

Это сохраняет this! Использование этого метода в машинописном тексте требует, чтобы элемент был any или же создавал подтип.

Old Badman Grey 06.04.2017 04:49

someInput.setAttribute («класс», «демокласс»);

bh_earth0 28.12.2017 17:57

Мои переменные продолжают возвращаться как неопределенные ... есть мысли о том, как это исправить?

nomaam 05.09.2018 04:48

Это правильный ответ, и это даже метод, который jQuery использует для передачи аргументов. За исключением того, что они хранят его в evt.data.myParam, но достаточно близко.

beliha 26.03.2019 10:59

Если addEventListener предназначен для document, evt.target.myParam у меня не работал. Вместо этого мне пришлось использовать evt.currentTarget.myParam.

turrican_34 08.07.2019 21:15

гораздо более элегантное решение.

sh6210 28.01.2021 14:43

Это старый вопрос, но я подумал, что предлагаю альтернативу с использованием ES5 .bind() - для потомков. :)

function some_func(otherFunc, ev) {
    // magic happens
}
someObj.addEventListener("click", some_func.bind(null, some_other_func), false);

Просто имейте в виду, что вам нужно настроить свою функцию прослушивателя с первым параметром в качестве аргумента, который вы передаете в bind (ваша другая функция), а второй параметр теперь является событием (вместо первого, как это было бы) .

Function.prototype.bind () действительно лучший способ решить эту проблему. Кроме того, он интуитивно работает внутри циклов - вы получаете желаемую лексическую область видимости. Никаких анонимных функций, IIFE или специальных свойств, привязанных к объектам.
Clint Pachl 11.03.2018 13:14

Посмотрите плюсы и минусы IIFE против bind ().

Clint Pachl 11.03.2018 13:17

Используя Function.prototype.bind(), вы не можете удалить прослушиватель событий, лучше вместо этого использовать функцию каррирования (см. Ответ @ tomcek112)

pldg 17.09.2019 19:01

ПРИМЕЧАНИЕ. some_other_func - это переменная, вы можете передать в some_func любое значение.

hitautodestruct 07.01.2020 22:41

Function.prototype.bind () - это способ привязать целевую функцию к определенной области и дополнительно определить объект this в целевой функции.

someObj.addEventListener("click", some_function.bind(this), false);

Или захватить часть лексической области видимости, например, в цикле:

someObj.addEventListener("click", some_function.bind(this, arg1, arg2), false);

Наконец, если параметр this не нужен в целевой функции:

someObj.addEventListener("click", some_function.bind(null, arg1, arg2), false);

Вы можете просто связать все необходимые аргументы с помощью bind:

root.addEventListener('click', myPrettyHandler.bind(null, event, arg1, ... ));

Таким образом, вы всегда будете получать event, arg1 и другие вещи, передаваемые в myPrettyHandler.

http://passy.svbtle.com/partial-application-in-javascript-using-bind

Спасибо! Уже пробовал .bind(), но без нуля в качестве первого параметра. что не сработало.

Larphoid 29.12.2018 22:47

нет необходимости в null, он отлично работает с .bind(event, arg1), по крайней мере, с VueJS.

DevonDahon 18.10.2019 09:55

Другая альтернатива, возможно, не такая элегантная, как использование bind, но она действительна для событий в цикле.

for (var key in catalog){
    document.getElementById(key).my_id = key
    document.getElementById(key).addEventListener('click', function(e) {
        editorContent.loadCatalogEntry(e.srcElement.my_id)
    }, false);
}

Он был протестирован для расширений Google Chrome, и, возможно, e.srcElement необходимо заменить на e.source в других браузерах.

Я нашел это решение, используя комментарий, опубликованный Иматория, но я не могу отметить его как полезный, потому что у меня недостаточно репутации: D

Следующий ответ верен, но приведенный ниже код не работает в IE8, если предположим, что вы сжали файл js с помощью yuicompressor. (Фактически, все еще большинство людей в США используют IE8)

var someVar; 
someVar = some_other_function();
alert(someVar);
someObj.addEventListener("click",
                         function(){
                          some_function(someVar);
                         },
                         false);

Итак, мы можем исправить указанную выше проблему следующим образом, и она отлично работает во всех браузерах.

var someVar, eventListnerFunc;
someVar = some_other_function();
eventListnerFunc = some_function(someVar);
someObj.addEventListener("click", eventListnerFunc, false);

Надеюсь, это будет полезно для тех, кто сжимает файл js в производственной среде.

Удачи!!

Внутри всех функций есть специальная переменная: аргументы. Вы можете передать свои параметры как анонимные параметры и получить к ним доступ (по порядку) через переменную аргументы.

Пример:

var someVar = some_other_function();
someObj.addEventListener("click", function(someVar){
    some_function(arguments[0]);
}, false);

Хм ... В чем причина отрицательного голоса? Если это было не то, что вы искали, пожалуйста, более четко объясните, что вы имеете в виду (я знаю, что на этот вопрос уже дан ответ). Но разве мой код не отвечает на то, о чем вы просили? Специальная переменная «arguments» дает вам доступ ко всем параметрам внутри функции.

StanE 03.03.2015 02:07

Вот еще один способ (он работает внутри циклов):

var someVar = some_other_function();
someObj.addEventListener("click", 

function(theVar){
    return function(){some_function(theVar)};
}(someVar),

false);

Это лучший способ. Уродливо, но эффективно внутри циклов, поскольку отправка аргумента в анонимную функцию захватит переменную.

bob 03.07.2015 00:45

Следующий код отлично работал у меня (firefox):

for (var i=0; i<3; i++) {
   element = new ...   // create your element
   element.counter = i;
   element.addEventListener('click', function(e){
        console.info(this.counter);
        ...            // another code with this element
   }, false);
}

Выход:

0
1
2

Что это вообще такое?

NiCk Newman 06.07.2015 15:27

Отправка аргументов функции обратного вызова eventListener требует создания изолированной функции и передачи аргументов этой изолированной функции.

Вот небольшая полезная вспомогательная функция, которую вы можете использовать. На основе приведенного выше примера "привет, мир".)

Также необходимо поддерживать ссылку на функцию, чтобы мы могли аккуратно удалить слушателя.

// Lambda closure chaos.
//
// Send an anonymous function to the listener, but execute it immediately.
// This will cause the arguments are captured, which is useful when running 
// within loops.
//
// The anonymous function returns a closure, that will be executed when 
// the event triggers. And since the arguments were captured, any vars 
// that were sent in will be unique to the function.

function addListenerWithArgs(elem, evt, func, vars){
    var f = function(ff, vv){
            return (function (){
                ff(vv);
            });
    }(func, vars);

    elem.addEventListener(evt, f);

    return f;
}

// Usage:

function doSomething(withThis){
    console.info("withThis", withThis);
}

// Capture the function so we can remove it later.
var storeFunc = addListenerWithArgs(someElem, "click", doSomething, "foo");

// To remove the listener, use the normal routine:
someElem.removeEventListener("click", storeFunc);

Это ответ от 15 года, но это именно то, что мне нужно для решения этой проблемы с помощью хука useRef. Если вы используете перехватчик ref и вам нужен слушатель для него, который вы можете очистить при размонтировании компонента, вот и все. Четвертый аргумент storeFunc должен быть вашей переменной ref. Включите удаление вашего слушателя в useEffect, и все готово: useEffect(() => { return () => { window.removeEventListener('scroll', storeFunc, false); } }, [storeFunc])

Rob B 05.09.2019 17:48
    var EV = {
        ev: '',
        fn: '',
        elem: '',
        add: function () {
            this.elem.addEventListener(this.ev, this.fn, false);
        }
    };

    function cons() {
        console.info('some what');
    }

    EV.ev = 'click';
    EV.fn = cons;
    EV.elem = document.getElementById('body');
    EV.add();

//If you want to add one more listener for load event then simply add this two lines of code:

    EV.ev = 'load';
    EV.add();

Один из способов сделать это с помощью внешняя функция:

elem.addEventListener('click', (function(numCopy) {
  return function() {
    alert(numCopy)
  };
})(num));

Этот метод заключения анонимной функции в круглые скобки и немедленного ее вызова называется IIFE (Immediately-Invoked Function Expression).

Вы можете проверить пример с двумя параметрами в http://codepen.io/froucher/pen/BoWwgz.

catimg.addEventListener('click', (function(c, i){
  return function() {
    c.meows++;
    i.textContent = c.name + '\'s meows are: ' + c.meows;
  }
})(cat, catmeows));

Для меня хорошо сработал следующий подход. Изменено из здесь.

function callback(theVar) {
  return function() {
    theVar();
  }
}

function some_other_function() {
  document.body.innerHTML += "made it.";
}

var someVar = some_other_function;
document.getElementById('button').addEventListener('click', callback(someVar));
<!DOCTYPE html>
<html>
  <body>
    <button type = "button" id = "button">Click Me!</button>
  </body>
</html>

Я застрял в этом, поскольку использовал его в цикле для поиска элементов и добавления к нему списка. Если вы используете его в цикле, то это будет отлично работать.

for (var i = 0; i < states_array.length; i++) {
     var link = document.getElementById('apply_'+states_array[i].state_id);
     link.my_id = i;
     link.addEventListener('click', function(e) {   
        alert(e.target.my_id);        
        some_function(states_array[e.target.my_id].css_url);
     });
}

Вы можете передать somevar по значению (не по ссылке) с помощью функции javascript, известной как закрытие:

var someVar='origin';
func = function(v){
    console.info(v);
}
document.addEventListener('click',function(someVar){
   return function(){func(someVar)}
}(someVar));
someVar='changed'

Или вы можете написать обычную функцию переноса, например wrapEventCallback:

function wrapEventCallback(callback){
    var args = Array.prototype.slice.call(arguments, 1);
    return function(e){
        callback.apply(this, args)
    }
}
var someVar='origin';
func = function(v){
    console.info(v);
}
document.addEventListener('click',wrapEventCallback(func,someVar))
someVar='changed'

Здесь wrapEventCallback(func,var1,var2) выглядит так:

func.bind(null, var1,var2)

Большое спасибо за этот ответ! OP не искал этого, но я думаю, что люди, которые набирают «Как передать аргументы в addEventListener» в Google, будут искать ваш ответ. Просто нужно немного больше пояснений :) Я редактирую.

Sindarus 10.08.2016 20:50

Довольно старый вопрос, но сегодня у меня была такая же проблема. Самым чистым решением, которое я нашел, является использование концепции карри.

Код для этого:

someObj.addEventListener('click', some_function(someVar));

var some_function = function(someVar) {
    return function curried_func(e) {
        // do something here
    }
}

Называя каррированную функцию, вы можете вызвать Object.removeEventListener, чтобы отменить регистрацию eventListener в более позднее время выполнения.

Рад встретить этот ответ, в котором упоминается каррированная функция. Как бы вы удалили прослушиватель событий?

bob 24.09.2017 18:43

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

Matthew Brent 01.05.2018 18:16

Этот ответ будет регистрировать функцию столько раз, сколько вызывается addEventListener, поскольку some_function (var) каждый раз возвращает вновь созданную функцию.

Yahia 25.06.2019 10:27

Мне не нравится идея называть каррированную функцию, чтобы удалить слушателя, потому что тогда ur имеет дело с двумя пространствами имен diff, которые вы должны отслеживать

oldboy 19.11.2019 03:24

как использовать стрелочную функцию для каррированного fn?

Kenzo 23.10.2020 21:17

У меня это не работает, так как curried_func недоступен вне some_function. Что терпит неудачу, так это: someObj.removeEventListener('click', curried_func);. Может, я как-то неверно истолковал ваш ответ.

martin36 23.03.2021 17:39

Тебе нужно:

newElem.addEventListener('click', {
    handleEvent: function (event) {
        clickImg(parameter);
    }
});

Это решение может хорошо выглядеть

var some_other_function = someVar => function() {
}

someObj.addEventListener('click', some_other_function(someVar));

или привязать ценности тоже будет хорошо

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

// Possible:
function myCallback() { /* code here */ }
someObject.addEventListener('event', myCallback);
someObject.removeEventListener('event', myCallback);

// Not Possible:
function myCallback() { /* code here */ }
someObject.addEventListener('event', function() { myCallback });
someObject.removeEventListener('event', /* can't remove anonymous function */);

Так что имейте это в виду.

Если вы используете ES6, вы можете сделать то же самое, но немного чище:

someObject.addEventListener('event', () => myCallback(params));
    $form.addEventListener('submit', save.bind(null, data, keyword, $name.value, myStemComment));
    function save(data, keyword, name, comment, event) {

Вот как я правильно прошел мероприятие.

Отлично, вот как я почти закончил - просто неправильно передал дополнительное событие в bind, когда его нет (например, в angular), которое автоматически приходит в этом случае.

Manohar Reddy Poreddy 20.10.2019 07:59

Да, это работает. Спасибо. Что такое ноль в первом аргументе? А как еще передать этот объект на привязку?

Rishabh Gupta 31.07.2020 14:19

хорошая однострочная альтернатива

element.addEventListener('dragstart',(evt) => onDragStart(param1, param2, param3, evt));
function onDragStart(param1, param2, param3, evt) {

 //some action...

}

Возможно, не оптимально, но достаточно просто для тех, кто не разбирается в супер js. Поместите функцию, вызывающую addEventListener, в отдельную функцию. Таким образом, любые передаваемые в него значения функции сохраняют свою собственную область видимости, и вы можете перебирать эту функцию сколько угодно.

Пример Я работал с чтением файлов, поскольку мне нужно было захватить и отрендерить предварительный просмотр изображения и имени файла. Мне потребовалось некоторое время, чтобы избежать асинхронных проблем при использовании нескольких типов загрузки файлов. Я случайно увидел одно и то же «имя» на всех рендерах, несмотря на то, что загружал разные файлы.

Первоначально вся функция readFile () находилась внутри функции readFiles (). Это вызвало проблемы с асинхронной областью видимости.

    function readFiles(input) {
      if (input.files) {
        for(i=0;i<input.files.length;i++) {

          var filename = input.files[i].name;

          if ( /\.(jpe?g|jpg|png|gif|svg|bmp)$/i.test(filename) ) {
            readFile(input.files[i],filename);
          }
       }
      }
    } //end readFiles



    function readFile(file,filename) {
            var reader = new FileReader();

            reader.addEventListener("load", function() { alert(filename);}, false);

            reader.readAsDataURL(file);

    } //end readFile

просто хотел бы добавить. если кто-то добавляет функцию, которая обновляет флажки в прослушивателе событий, вам придется использовать event.target вместо this для обновления флажков.

В 2019 году много изменений api, лучший ответ больше не работает, без исправления ошибки.

поделитесь рабочим кодом.

Вдохновленный всем вышеперечисленным ответом.

 button_element = document.getElementById('your-button')

 button_element.setAttribute('your-parameter-name',your-parameter-value);

 button_element.addEventListener('click', your_function);


 function your_function(event)
   {
      //when click print the parameter value 
      console.info(event.currentTarget.attributes.your-parameter-name.value;)
   }

У меня очень упрощенный подход. Это может сработать для других, поскольку помогло мне. Это... Когда у вас есть несколько элементов / переменных, которым назначена одна и та же функция, и вы хотите передать ссылку, самым простым решением является ...

function Name()
{

this.methodName = "Value"

}

Вот и все. У меня это сработало. Так просто.

Поскольку ваш прослушиватель событий - click, вы можете:

someObj.setAttribute("onclick", "function(parameter)");

Другие вопросы по теме