0

I found this question on interviewcake.com.

<button id="btn-0">Button 1!</button>
<button id="btn-1">Button 2!</button>
<button id="btn-2">Button 3!</button>

<script type="text/javascript">
    var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
    for (var btnNum = 0; btnNum < prizes.length; btnNum++) {
        document.getElementById('btn-' + btnNum).onclick = function() {
            alert(prizes[btnNum]);
        };
    }
</script>

on click of any button it alerts 'undefined'. Can't figure out this unexpected behavior. Your help is highly appreciated.

  • Closures is the issue here. – Mr. Alien Jan 19 '17 at 06:02
  • The problem with your variable `btnNum` in your case `btnNum ` is an global variable and incremented on each iteration and finally `btnNum value is 3` and `prizes have not 3rd index` that's why you got undefined. – Umair Ahmed Jan 19 '17 at 06:44
  • I found a great article on this. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures – Priyatam Roy Jan 19 '17 at 07:08

2 Answers2

1

As I already commented, closures were the issue, you can use an anonymous function here and pass btnNum as param.

var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
for (var btnNum = 0; btnNum < prizes.length; btnNum++) {
  (function(x) {
    document.getElementById('btn-' + x).onclick = function() {
      alert(prizes[x]);
    };
  })(btnNum);
}

Demo


If you are fine using ES6 syntax, you can use let keyword instead of var

var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
for (let btnNum = 0; btnNum < prizes.length; btnNum++) {
  //--^--
  document.getElementById('btn-' + btnNum).onclick = function() {
    alert(prizes[btnNum]);
  };
}
GantTheWanderer
  • 1,255
  • 1
  • 11
  • 19
Mr. Alien
  • 153,751
  • 34
  • 298
  • 278
0

There is a closure in the for loop. So your btnNum will always be 3 in onclick

    var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
    for (var btnNum = 0; btnNum < prizes.length; btnNum++) {
      console.log(prizes);
      document.getElementById('btn-' + btnNum).onclick = function() {
        alert(prizes[this.id.replace('btn-', '')]);
      };
    }
<button id="btn-0">Button 1!</button>
<button id="btn-1">Button 2!</button>
<button id="btn-2">Button 3!</button>
Kishore Kumar
  • 12,675
  • 27
  • 97
  • 154