If you are a person that JavaScript(JS) is not your first programming language, and you have a background in C, C++, Java, C#, Python or other well structured programming languages, then you might caught off-guard with some JS concepts. We usually don’t like to start learning something from zero, so we usually try to guess how things work based on what we already learned in other programming languages. But some concepts in JS are totally different from other languages, and the one that recently I faced is: Variable Scope.
What is the Variable Scope in Javascript?
Well, it might look strange, but it seems everything in Javascript has some sort of relationship with functions. The scope of Variables in Javascript is the function that the variable has been defined in it. If it is not inside any function, then it is global. Also functions have same scope as variables.
For a long time, I was assuming that the variable scope is somehow same as C++ or C# (on code block level which will be indicated by curly braces ({}) or based on indentation in Python), and this is because I didn’t spend enough time to check the basic concepts (it is really boring to read those lengthy books/documents) and it seems I am not alone and lots of web developers are on the same page.
A Common Example: Infamous JavaScript Loop Variable
This is very common case and there are plenty of discussions and solutions for this problem. Let’s say you have a look that generates some links and keep adding them to the document, and the functionality of the link is somehow dependent to the order link being added.
function addLinks () { for (var i=0, link; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function () { alert(i); }; document.body.appendChild(link); } } addLinks();
If you run above code you will see 5 links, but if you click on any of them, it will alert 5 rather than the proper index. The reason is, sine the anonymous function for onclick didn’t run yet, it will keep a reference to the variable i, that it’s value is 5 after the loop. For better understanding, you can simply move the “var i” to the first line of the function as below:
function addLinks () { var i, link; for (i=0; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function () { alert(i); }; document.body.appendChild(link); } } addLinks();
Now you can see why the final result is always 5. There are different ways to solve this, one way is to make a new scope inside the loop, so rather than reference to the i, its value will be used. Below you can find the updated code.
function addLinks () { var i, link; for (i=0; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function(linkIndex){ return function () { alert(linkIndex); }; }(i); document.body.appendChild(link); } } addLinks();
Here what we’ve done is, we defined new anonymous function which returns our on click handler, but notice we have called this anonymous function. Since during the loop, the function has been called, the value of the loop variable will be stored rather than its reference. This method called Function Closure. If you are using JS frameworks, such, as jQuery, then you might saw this before (on creating new plug-in).
Using closure is fine, but you have to consider efficiency as well and at least for this sample code, it is over kill. Another way to deal with this issue is using DOM to store the value for us. So we can update the above code to something like below:
function linkHandler(){ alert(thisgetAttribute("data-i")); } function addLinks () { var i, link; for (i=0; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.setAttribute("data-i" , i); link.onclick = linkHandler; document.body.appendChild(link); } } addLinks();
Here we are simply storing the value in DOM object, and on the handler we will just use that value. This is easier and also debugging it is easier because you can see the value on the generated item as well.
This is what I’ve faced so many times from the time I have started using JS, but recently I dig into it. Hope you will find it useful as well.
