JavaScript for C# Developers: 4. Variable Scope
As C# developers we think we know what variable scope is all about. But if I showed you the JavaScript code below, what number would you think would be shown in the alert dialog.
var foo = 1; function bar(a) { if (a == 1) { var foo = 10; } alert(foo); } bar(1);
If you answered 10 then you either guessed right or you understand JavaScript’s variable scoping and you probably don’t need to read any further, but for most C# developers this feels strange. This is one of those areas where, in my opinion, it was wrong for the creators of JavaScript to make it look like a C language, as this makes us believe that it behaves like a C language.
In C type languages variables are scoped at the “block” level. When control enters a block like an if statement or a for loop then new variables can be defined inside that block without affecting the variable(s) in the outer block. This is demonstrated in the C# code shown below.
public int main() { int x = 1; Console.Write(x); // 1 if (true) { int x = 2; Console.Write(x); // 2 } Console.Write(x); // 1 }
In this example when the control flow enters the if block the variable x is redefined (technically a new variable is created) so it contains the value 2 but once control returns to the main method the original variable x still has its initial value.
In the same code written in JavaScript the value of x at the last statement is 2 because the x variable inside the if block is the same variable as the one outside (see below)
function main() { var x = 1; console.log(x); // 1 if (true) { var x = 2; console.log(x); // 2 } console.log(x); // 2 }
There is, luckily a way we can fake the idea of block level scope because of the flexibility of JavaScript functions. We use what is called a self invoking or self executing anonymous function to simulate our block. The variables defined inside this function have function scope within the function.
function main() { var x = 1; console.log(x); // 1 if (true) { (function () { var x = 2; console.log(x); // 2 }()); } console.log(x); // still 1 }
This approach is quite flexible and can be used anywhere that we need to create a temporary scope for a variable. But it should not be over-used as a mechanism to make JavaScript work like C#.