HTML5 Zone is brought to you in partnership with:

Axel Fontaine is a software development expert and freelance consultant based in Munich. He is specialized in Continuous Delivery. He has extensive experience with the full software development lifecycle. He hates complexity with a passion. As an architect, developer, coach and consultant he helps his customers improve the way they develop and deliver software. To alleviate one of the traditional pain points, he started Flyway, the Agile Database Migration Framework for Java. He frequently speaks at Java User Groups. Axel is a DZone MVB and is not an employee of DZone and has posted 7 posts at DZone. You can read more from them at their website. View Full User Profile

The perils of the missing javascript block scope

02.06.2013
| 1840 views |
  • submit to reddit

Javascript variable scope is something of a strange thing. You have a global and a function scope. But unlike most other languages, there is no block scope! This is often a cause for hard to find bugs.

Let me show you the consequences of this with a small puzzler:

<html>
<body>
<a id="link1" href="">Link 1</a> <span id="part1"></span><br/>
<a id="link2" href="">Link 2</a> <span id="part2"></span><br/>
<a id="link3" href="">Link 3</a> <span id="part3"></span><br/>
<a id="link4" href="">Link 4</a> <span id="part4"></span><br/>
<a id="link5" href="">Link 5</a> <span id="part5"></span><br/>
No Link 6 <span id="part6"></span><br/>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
  $(document).ready(function() {
    for (i = 1; i <= 5; i++) {
      $("#link"+i).click(function() {
        $("#part"+i).html("Clicked !");
        return false;
      });
    }
  });
</script>
</body>
</html>

Now what does this do? (you need a bit of jquery knowledge to guess it)

At first glance, it walks over the 5 links present on this page, and registers a handler for mouse clicks that adds the text "Clicked !" to the span element with the same number as the link.

Or does it?

Well, this is what the output looks like when you click on "Link 3":

Test


It is totally wrong ! Now why is that? Well, as we have no block scope, by the time we are done with the for loop, the variable i has been incremented up to 6. It is however still in scope, and therefore this last value gets used when the closure for the click event gets called. And so it is part 6 that receives the new text !

So how can we fix this?

We have to separate the scopes, and to do that we need a new function. This is what the correct code looks like:
<html>
<body>
<a id="link1" href="">Link 1</a> <span id="part1"></span><br/>
<a id="link2" href="">Link 2</a> <span id="part2"></span><br/>
<a id="link3" href="">Link 3</a> <span id="part3"></span><br/>
<a id="link4" href="">Link 4</a> <span id="part4"></span><br/>
<a id="link5" href="">Link 5</a> <span id="part5"></span><br/>
No Link 6 <span id="part6"></span><br/>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
  $(document).ready(function() {
    for (i = 1; i <= 5; i++) {
      addClickEvent(i);
    }
  });
  
  function addClickEvent(i) {
    $("#link"+i).click(function() {
      $("#part"+i).html("Clicked !");
      return false;
    });
  }
</script>
</body>
</html>

With the registration of the click event taking place in a separate function (and therefore a separate scope for the variable i), this is what the output looks like:

Test OK


Which is much more like what we were expecting !

So beware of the lack of block scope in Javascript! It can come and bite more easily than you think if you're not extra careful about it!


Published at DZone with permission of Axel Fontaine, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)