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_function와 someVar액세스 할 수 있어야합니다, 경우에 그들은 익명 곳 맥락에서 사용할 수 있었던

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.