addEventListener 리스너 함수에 인수를 전달하는 방법은 무엇입니까?


304

상황은 다소

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

문제는 someVar의 리스너 함수 내 에서 값이 보이지 않아 addEventListener새 변수로 취급 될 수 있다는 것입니다.


8
이 문제에 대한 매우 명확한 기사 : toddmotto.com/avoiding-anonymous-javascript-functions
Nobita

가장 깨끗한 방법은 아니지만 일을합니다. someVar가 숫자 나 텍스트 만 가능한 경우 eval ( 'someObj.addEventListener ( "click", function () {some_function ('+ someVar + ');});');
Ignas2526

그냥 오늘이 문제를 가지고 있었다 - 여기 주어진 솔루션 (다른 솔루션 등, 루프 문제에 대한 같은 문제가) 올 - stackoverflow.com/a/54731362/984471
Manohar 레디 Poreddy

답변:


206

작성한 코드에는 아무런 문제가 없습니다. 모두 some_functionsomeVar액세스 할 수 있어야합니다, 경우에 그들은 익명 곳 맥락에서 사용할 수 있었던

function() { some_function(someVar); } 

만들어졌습니다.

경고가 원하는 값을 제공하는지 확인하십시오. 익명 함수 범위 내에서 액세스 할 수 있는지 확인하십시오 ( someVar에 대한 호출 옆에 동일한 변수 에서 작동하는 코드가 더없는 경우 addEventListener)

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

86
for 루프에서는 작동하지 않습니다. 나는 항상 그 반복에 속한 것이 아니라 최신 가치를 얻습니다. 어떤 해결책?
iMatoria

6
왜 루프에서 작동하지 않는지 아는 사람이 있습니까? 그 행동의 이유는 무엇입니까?
Morfidon

3
전역 변수를 가진 함수 는 자바 스크립트에서 클로저 역할을하기 때문에 @Morfidon 때문에 어휘 범위 밖의 환경을 기억한다는 의미이다. 동일한 환경에서 다른 기능을 만들면 동일한 환경을 참조합니다.
bugwheels94

16
@ Morfidon : 루프에서 someVar의 값은 리스너가 추가되었을 때의 값이 아니라 리스너가 실행될 때의 값입니다. 리스너가 실행될 때 루프는 이미 종료되었으므로 someVar의 값은 루프가 종료되었을 때의 값이됩니다.
www.admiraalit.nl

4
@iMatoria 방금 메소드를 bound function사용하여 작성하면 .bind()루프 developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Luke T O'Brien

353

왜 이벤트의 대상 속성에서 인수를 가져 오지 않습니까?

예:

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는 프로토 타입 지향 언어입니다. 기억하십시오!


16
이것은 'removeEventListener'함수 다음에 사용할 수 있기 때문에 정답입니다.
user5260143

14
그렇지 evt.currentTarget.myParam않습니까? 'someInput'내부에 다른 요소가있는 evt.target경우 내부 요소를 참조 할 수 있습니다. ( jsfiddle.net/qp5zguay/1 )
Herbertusz

이것은 보존합니다 this! typescript에서이 메소드를 사용하려면 요소가 any하위 유형이거나 하위 유형 이어야 합니다.
Old Badman Grey

1
내 변수는 정의되지 않은 상태로 계속 돌아옵니다 ... 고치는 방법에 대한 생각?
nomaam

1
경우 addEventListener입니다 document, evt.target.myParam나를 위해 작동하지 않았다. evt.currentTarget.myParam대신 사용해야 했습니다.
turrican_34

67

이 질문은 오래되었지만 후손을 위해 ES5의 .bind ()를 사용하는 대안을 제공 할 것이라고 생각했습니다. :)

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

bind에 전달할 인수로 첫 번째 param (다른 함수)으로 리스너 함수를 설정해야하며 두 번째 param은 이제 이벤트가됩니다 (첫 번째 대신) .


1
Function.prototype.bind () 는 실제로이 문제를 해결하는 가장 좋은 방법입니다. 또한 루프 내부에서 직관적으로 작동하므로 원하는 어휘 범위를 얻을 수 있습니다. 익명 함수, IIFE 또는 객체에 고정 된 특수 속성이 없습니다.
클린트 Pachl

IIFE vs bind ()의 장단점을 참조하십시오 .
클린트 Pachl

1
를 사용 Function.prototype.bind()하면 이벤트 리스너를 제거 할 수 없으므로 대신 카레 기능을 사용하는 것이 좋습니다 (@ tomcek112 답변 참조)
pldg

참고 : some_other_func변수이며 원하는 값을 전달할 수 있습니다 some_func.
hitautodestruct

28

필요한 모든 인수를 'bind'로 바인딩 할 수 있습니다.

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

이러한 방법으로 당신은 항상거야 event, arg1전달 및 기타 물건을 myPrettyHandler.

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


감사! 이미 시도 .bind()했지만 첫 번째 매개 변수로 null이 없었습니다. 작동하지 않았습니다.
Larphoid

적어도 VueJS null에서는 작동 하지 않습니다 .bind(event, arg1).
DevonDahon

27

아주 오래된 질문이지만 오늘도 같은 문제가있었습니다. 내가 찾은 가장 깨끗한 해결책은 카레 개념을 사용하는 것입니다 .

그 코드 :

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

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

커리 함수의 이름을 지정하면 나중에 실행 시간에 eventListener를 등록 취소하기 위해 Object.removeEventListener를 호출 할 수 있습니다.


4
카레 기능을 언급 한이 답변을 만나게되어 기쁩니다. 그래도 이벤트 리스너를 어떻게 제거 하시겠습니까?
bob

3
좋은 용어를 볼 수 있습니다. 커리 기능의 이름을 지정하여 이벤트 리스너를 제거 할 수 있어야합니다. 편집을 제안하겠습니다.
매튜 브렌트

이 응답은 some_function (var)이 매번 새로 작성된 함수를 리턴하므로 addEventListener가 호출 될 때마다 함수를 등록합니다.
Yahia

리스너 cuz를 제거하기 위해 커리 함수의 이름을 지정해야한다는 생각이 마음에
들지 않습니다. 그러면

19

함수를 변수로 선언하여 인수로 이벤트 리스너를 추가 및 제거 할 수 있습니다.

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

newSrc매개 변수로 myaudio를 사용하는 메소드 funcName는 함수 이름 변수입니다.

리스너를 제거 할 수 있습니다 myaudio.removeEventListener('ended',func,false);


12

클로저로 알려진 자바 스크립트 기능을 통해 somevar를 값으로 (참조가 아닌) 전달할 수 있습니다 .

var someVar='origin';
func = function(v){
    console.log(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.log(v);
}
document.addEventListener('click',wrapEventCallback(func,someVar))
someVar='changed'

여기는 다음 wrapEventCallback(func,var1,var2)과 같습니다

func.bind(null, var1,var2)

1
이 답변에 감사드립니다! OP는 이것을 찾지 않았지만 Google에 "addEventListener에 인수를 전달하는 방법"을 입력하는 사람들이 귀하의 답변을 찾고 있다고 생각합니다. 좀 더 설명이 필요합니다 :) 편집하고 있습니다.
Sindarus 2016 년

9

someVar값은 some_function()리스너가 아닌 컨텍스트 에서만 액세스 할 수 있어야합니다 . 리스너 내에서 사용하려면 다음과 같은 작업을 수행해야합니다.

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

사용이 newVar대신.

다른 방법은 리스너에서 새로운 로컬 변수로 사용하여 someVar값 을 반환 some_function()하는 것입니다.

var someVar = some_function(someVar);

9

또 다른 방법이 있습니다 (이 방법은 for 루프 내에서 작동합니다).

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

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

false);

2
이것이 가장 좋은 방법입니다. 추악하지만 익명 함수에 인수를 보내면 var가 캡처되므로 루프 내에서 효과적입니다.
bob

9

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);

7

사용하다

   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

4
    $form.addEventListener('submit', save.bind(null, data, keyword, $name.value, myStemComment));
    function save(data, keyword, name, comment, event) {

이것이 이벤트가 올바르게 전달되는 방법입니다.


훌륭합니다. 이것은 내가 거의 결론 지은 방법입니다. 바인딩이 없을 때 (앵귤러와 같이) 바인딩에서 여분의 이벤트를 잘못 전달했습니다.이 경우 자동으로 발생합니다.
Manohar Reddy Poreddy

3

eventListener의 콜백 함수에 인수를 보내려면 격리 된 함수를 작성하고 해당 격리 된 함수에 인수를 전달해야합니다.

사용할 수있는 멋진 도우미 기능이 있습니다. 위의 "hello world 's 예제를 기반으로합니다.)

리스너를 깨끗하게 제거 할 수 있도록 함수에 대한 참조를 유지하는 것도 필요합니다.

// 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.log("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 후크를 사용 하여이 문제를 처리하는 데 필요한 것입니다. 참조 후크를 사용 중이고 구성 요소 마운트 해제를 정리할 수있는 리스너가 필요한 경우 이것이 리스너입니다. 네 번째 인수 storeFunc는 ref 변수 여야합니다. 리스너 제거 사용하기 다음과 같이 효과가 있습니다.useEffect(() => { return () => { window.removeEventListener('scroll', storeFunc, false); } }, [storeFunc])
Rob B

3

한 가지 방법은 외부 함수를 사용 하여이 작업을 수행하는 것입니다 .

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

익명 함수를 괄호로 묶고 즉시 호출하는이 방법을 IIFE (즉시 호출 함수 표현식)라고합니다.

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));

3

내가 함수를 호출하는 것을 잘못 사용하지 않으면 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));

3

좋은 한 줄 대안

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

 //some action...

}

2

또한 다음을 시도하십시오 (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

2

요소를 찾고 리스터를 추가하기 위해 루프에서 사용 하면서이 문제가 발생했습니다. 루프에서 사용하면 완벽하게 작동합니다.

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);
     });
}

2

2019 년에는 많은 버그 변경이 있었으며 수정 버그없이 가장 좋은 대답은 더 이상 작동하지 않습니다.

작동 코드를 공유하십시오.

위의 모든 대답에서 영감을 얻었습니다.

 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.log(event.currentTarget.attributes.your-parameter-name.value;)
   }

1

모든 함수에는 특별한 변수가 있습니다 : arguments . 매개 변수를 익명 매개 변수로 전달하고 arguments 변수를 통해 순서대로 액세스 할 수 있습니다 .

예:

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

흠 ... downvote의 이유는 무엇입니까? 그것이 당신이 찾고있는 것이 아니라면, 당신이 의미하는 바를 더 명확하게 설명하십시오 (질문에 이미 답변되어 있음을 알고 있습니다). 그러나 내 코드가 당신이 요청한 것에 응답하지 않습니까? 특수 변수 "인수"를 사용하면 함수 내부의 모든 매개 변수에 액세스 할 수 있습니다.
StanE

1
    var EV = {
        ev: '',
        fn: '',
        elem: '',
        add: function () {
            this.elem.addEventListener(this.ev, this.fn, false);
        }
    };

    function cons() {
        console.log('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();

1

다음 접근 방식이 저에게 효과적이었습니다. 여기 에서 수정했습니다 .

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>


0

다음 대답은 정확하지만 yuicompressor를 사용하여 js 파일을 압축했다고 가정하면 IE8에서 아래 코드가 작동하지 않습니다. (실제로 대부분의 미국 사람들은 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 파일을 압축하는 일부 사용자에게 유용 할 것입니다.

행운을 빕니다!!


0

다음 코드는 나를 위해 잘 작동했습니다 (firefox).

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

산출:

0
1
2

이게 세상에서 뭐야?
NiCk Newman

0

당신이 필요합니다 :

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

0

아마도 최적은 아니지만 슈퍼 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

0

그냥 추가하고 싶습니다. 누구나 체크 박스를 이벤트 리스너에 업데이트하는 기능을 추가하는 경우 체크 박스를 업데이트하는 event.target대신 사용해야 합니다 this.


0

나는 매우 단순한 접근 방식을 가지고 있습니다. 이것은 다른 사람들에게 도움이 될 수 있습니다. 그것은 ... 같은 함수에 여러 요소 / 변수가 할당되어 있고 참조를 전달하려는 경우 가장 간단한 해결책은 ...

function Name()
{

this.methodName = "Value"

}

그게 다야. 그것은 나를 위해 일했다. 너무 간단합니다.


-1

바인드를 사용하는 것만 큼 우아하지는 않지만 다른 대안은 루프의 이벤트에 유효합니다.

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 크롬 확장 프로그램에 대해 테스트되었으며 다른 브라우저에서 e.srcElement를 e.source로 바꿔야 할 수도 있습니다.

Imatoria가 게시 한 의견을 사용 하여이 솔루션을 찾았 지만 평판이 충분하지 않아 유용하다고 표시 할 수 없습니다.


-1

이 솔루션은보기에 좋습니다.

var some_other_function = someVar => function() {
}

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

또는 유가 증권을 묶는 것도 좋습니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.