简体   繁体   中英

Can I pass “new” anonymous function to addEventListener

I use such code to pass arguments to event handler functions. But, in this particular case the loop is causing problems. Only the last linkTags[i] is accesible in all activeVisual calls. This has to do with the fact that the anonymous function that passes the argument is one and the same for the entire loop.

  for (var i = 0; i < linkTags.length; i++) {
    addCrossEvent(linkTags[i], "click", launchLink);
    addCrossEvent(linkTags[i], "mousedown", 
      function(evt) {
        activeVisual(evt, linkTags[i]);
      });
  }

Now, I remember trying to add new before the anonymous function declaration like this:

  for (var i = 0; i < linkTags.length; i++) {
    addCrossEvent(linkTags[i], "click", launchLink);
    addCrossEvent(linkTags[i], "mousedown", 
      new function(evt) {
        activeVisual(evt, linkTags[i]);
      });
  }

It did not work. The activeVisual never gets called. Can somebody explain to me why and how can I make it work, please?

UPDATE FINAL SOLUTION

Thanks to all responses below my WORKING code now looks like this:

  // Function that provides pass of event handling parameters with separate copy in each loop
  function callbackHandler(index) {
    return function(evt) {
      activeVisual(evt, linkTags[index]);
    }
  }
  ...
  for (var i = 0; i < linkTags.length; i++) {
    ...
    addCrossEvent(linkTags[i], "mousedown", callbackHandler(i));
  }

You need to do this:

addCrossEvent(linkTags[i], "mousedown", 
      (function(i) {
          return function(evt) {
              activeVisual(evt, linkTags[i]);
          }
      )(i);
);

The issue is with the iterator variable i which changes at each iteration, and a reference is passed of it, the value of i is not copied. Passing it this way as a parameter to a wrapper function, will cause a copy and it will receive the actual value at that particular iteration.

For completeness, here is an explanation why your way of using new does not work:

When you call a function with new , the function generates an empty object (which you can refer to with this inside the function and which inherits from the functions prototype) and returns it.
So you actually don't pass a function as callback handler, but the object returned by the function.

This is not a problem as long as the object implements the EventListner interface in order to be usable as event handler. If you do this, you could use your code with some modification:

  for (var i = 0; i < linkTags.length; i++) {
    addCrossEvent(linkTags[i], "click", launchLink);
    addCrossEvent(linkTags[i], "mousedown", 
      new (function(index) {
        this.handleEvent = function(evt) {
            activeVisual(evt, linkTags[index]);
        }
      })(i));
  }

This is actually similar to @Luca's answer, because the value of i is captured upon object creation. The upper code is actually identical to:

function CallbackHandler(index) {
    this.handleEvent = function(evt) {
        activeVisual(evt, linkTags[index]);
    }
}

for (var i = 0; i < linkTags.length; i++) {
    addCrossEvent(linkTags[i], "click", launchLink);
    addCrossEvent(linkTags[i], "mousedown", new CallbackHandler(i));
}

That said I find the usage of an immediate function that returns a function easier to read and I think using a function as event handler instead of an object is more common too.

Working DEMO

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM