0

I am having an issue regarding a reference.

The snippet is a minimal example that generates buttons with JS, which have events tied to a specific element on a page based on a variable within the code.

stuff = ['a', 'b', 'c']

for (var n of stuff) {
  e = document.createElement('button')
  e.innerText = 'Button ' + n
  e.id = n
  e.onclick = function() {
    document.getElementById(n).style.backgroundColor = '#dad'
  }
  document.body.append(e)
}

The buttons work and call their function, although n seems to "carry through" as a reference.

Attempting to negate this with n.slice() in the anonymous function does not seem to affect behaviour, even though it should cut out the reference (with the assumption that it returns a new variable, evaluated when the function is defined (instead of later when it is actually called)).

Off the top of my head, I cannot think of a way to pass information into the function in a way that would make each function unique in any way (for my use-case, I want the function to know what element called it, so if there's information in the event object that indicates the element that called it, then that would be very helpful for me also).

I'd also like to avoid passing the function as a string in setAttribute. (which would work, and I'm not even concerned about security at this point, but it feels like a hack).

Is there a canned solution or alternative approach that remedies the unwanted reference?

EDIT: I fixed the code by converting:

for (var n of stuff) {...

to

for (let n of stuff) {...

let has block-level scoping, and creates a new variable when used as an iterator, the difference in behaviour removes cross-referencing.

(Although I can think of uses where having one shared variable in a for loop would be useful, although declaring a var before the loop would communicate intent more clearly. tl;dr: let should probably be used to declare the iterator variable 99% of the time.

Magikarp
  • 171
  • 1
  • 11
  • 2
    Try to replace var to let :) – DraganS Oct 12 '22 at 22:45
  • stuff = ['a', 'b', 'c'] for (var n of stuff) { let e = document.createElement('button') e.innerText = 'Button ' + n e.id = n e.onclick = function() { document.getElementById(e.id).style.backgroundColor = '#dad' } document.body.append(e) } – user31782 Oct 12 '22 at 22:47
  • If you like var more then let - then switch to IIFE: e.onclick = ((m) => function() { document.getElementById(m).style.backgroundColor = '#dad' })(n) – DraganS Oct 12 '22 at 22:49
  • `let e = document.createElement('button')` + `e.style.backgroundColor = '#dad'` – Mister Jojo Oct 12 '22 at 22:51
  • 1
    @DraganS You should make that an answer because that fixed everything. I had no reason in particular for using var, I don't know the difference to let so now I have some reading to do. Thanks! =D – Magikarp Oct 12 '22 at 23:30

0 Answers0