0

I'm examining closure in loops with this approach most popular question on closure in JS

The thing I don't understand is where I change the code of closure. I try to pass value of 'help' as an argument to closure function.

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function makeHelpCallback(help) {

/// HERE'S THE CHANGE
  return function (help) {
// instead of return function () {
    showHelp(help);
  };
}

function setupHelp() {
  const helpText = [
    { id: 'email', help: 'Your e-mail address' },
    { id: 'name', help: 'Your full name' },
    { id: 'age', help: 'Your age (you must be over 16)' },
  ];

  for (let i = 0; i < 1; i++) {
    const item = helpText[i];
    document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
  }
}

setupHelp();

I expected the value of 'help' to be bound to the outer scope, so I would still get three times value of "Your age (you must be over 16)". However, I get [object FocusEvent]. I don't know how it's happening.

I tried to debug this with Chrome, but to no effect.

  • `onfocus` sends `FocusEvent` as an argument to the callback. In the original, the event was discarded because there was no callback parameter to bind the event. In your update, you bind the event to `help`, which then gets passed to `showHelp`. – Mulan Apr 28 '19 at 19:54
  • OK, it solves the problem of FocusEvent result. Thank you. – zapala.grzegorz Apr 28 '19 at 20:04

1 Answers1

1

You are shadowing you closure with the function argument of the same name when you do this:

function makeHelpCallback(help) {        // this<- |
                                         //        |
  return function (help) {  // <-- this shadows -  |
    showHelp(help);        // help is no longer refers to the closure it refers to the argument 
  };
}

If instead, you make an inner function that doesn't take a help argument, the help in the function body will refer to the outside closure:

function showHelp(help) {
  console.log(help)
}

function makeHelpCallback(help) {
  return function() {
    showHelp(help); // here help refers to the closure
  };
}

let f = makeHelpCallback("test1")
let f2 = makeHelpCallback("test2")

f()
f2()

If your inner function needs to take an argument, name it something else so it doesn't clobber the outside help.

Mark
  • 90,562
  • 7
  • 108
  • 148
  • Ok, it all sounds very reasonable. But I wondering why on earth I just can't pass down value of argument 'help'. Mhm, I see it that my inner function, with new argument, creates/accepts a brand new parameter, (which in effect makes the 'shadowing part'), and this ways discards the orginal help value. – zapala.grzegorz Apr 28 '19 at 20:12
  • @zapala.grzegorz exactly. – Mark Apr 28 '19 at 20:27