1

In the following example, concerning closures, I see this:

function addButtons(numButtons) {
  for (var i = 0; i < numButtons; i++) {
    var button = document.createElement('input');
    button.type = 'button';
    button.value = 'Button ' + (i + 1);
    button.onclick = function(buttonIndex) {
      return function() {
        alert('Button ' + (buttonIndex + 1) + ' clicked');
      };
    }(i);
    document.body.appendChild(button);
    document.body.appendChild(document.createElement('br'));
  }
}

window.onload = function() { addButtons(5); };

How come the onclick method isn't defined as follows?:

button.onclick = (function(buttonIndex) {
  return function() {
    alert('Button ' + (buttonIndex + 1) + ' clicked');
  };
})(i);

Doesn't an IIFE require the following syntax: (function statement)(arguments)?

trincot
  • 317,000
  • 35
  • 244
  • 286
Lev
  • 13,856
  • 14
  • 52
  • 84
  • Already answered here: http://stackoverflow.com/questions/31910216/why-are-parentheses-require-around-javascript-iife – Saravana Nov 01 '16 at 11:41
  • 1
    *"Doesn't an IFFE require the following syntax: (function statement)(arguments) ?"* No, immediately invoking a function itself does not require parens wrapping the function. What *is* needed is to ensure that the function is interpreted as a function expression instead of a declaration. Because the function is in the position of being the value of an assignment, it is already interpreted as an expression, so the parens aren't needed. Technically the parens themselves are not a requirement; any operator that receives the function as its expression should work. –  Nov 01 '16 at 11:52
  • If you are looking for alternatives, you can consider `.bind` instead – Rajesh Nov 01 '16 at 12:00

2 Answers2

0

You can use element's dataset. For example:

function addButtons(numButtons) {
  for (var i = 0; i < numButtons; i++) {
    var button = document.createElement('input');
    button.type = 'button';
    button.value = 'Button ' + (i + 1);
    button.dataset.buttonIndex = i + 1;
    button.onclick = function() {
      alert('Button ' + this.dataset.buttonIndex + ' clicked');
    };
    document.body.appendChild(button);
    document.body.appendChild(document.createElement('br'));
  }
}

window.onload = function() { addButtons(5); };
Eugene Tsakh
  • 2,777
  • 2
  • 14
  • 27
0

The original code works because the IIFE appears in an assignment, and so there is no ambiguity that the right part of the assignment is indeed an expression.

Without the assignment, the parser would misunderstand it to be a function declaration, and therefore would throw a syntax error, indicating that the declared function lacks a name. In that case the parentheses are necessary to make it an IIFE.

But it is common practice to always include the parentheses for an IIFE, even when used in an assignment.

In the concrete case you have at hand, you can also assign the click handler as using bind, which returns the function it needs:

button.onclick = function(buttonIndex) {
    alert('Button ' + (buttonIndex + 1) + ' clicked');
}.bind(null, i);
trincot
  • 317,000
  • 35
  • 244
  • 286