A friend of mine posted a short snippet of code on twitter, from something that he saw in another person’s code.
#javascript f not 4 closr ths shld bloup var f = function(){ if (true) {var v1= 1;} if(true) {var v2 =2;} return v1+v2; } console.log(f());
— Cullen Tsering (@CullenTsering) February 2, 2015
Here’s a slightly cleaned up version of this code:
The comment on his tweet was talking about how JavaScript allows variables to be declared inside curly braces, but still be used outside of theme. He had assumed that this was due to a closure, which wasn’t quite right.
It’s not closures that allow this to work. it is a combination of function scoped variables, and variable hoisting.
Variable Scope
The current, ES5 version of Javascript only has two scopes for variables: function scope and global scope.
By using a var
statement inside of a function, you are using a function-scoped variable, as is show in the example above.
In a browser, if you omit the var
statement, or if you use var
outside of any function, you will attach to the current global scope.
In a nodejs module / file, a variable declared outside of a function will be scoped to the module / file, because NodeJS/CommonJS modules are all wrapped in their own sandbox (function scope). You have to be more explicit to create a global variable in nodejs, and it is recommended you don’t do this.
Variable Hoisting
When you declare a variable inside of a function, the variable declaration is “hoisted” to the top of the function. That is, the runtime will move your variable declaration to the beginning of the function, in spite of where you put the var statement.
Because of this hoisting, it is recommended that you put variable declarations at the top of the function. It will happen for you anyways, so you may as well do this explicitly in order to prevent confusion about the code’s execution.
Rewriting The Function
Here is the equivalent function, making the implicit hoisting in to explicit variable declarations:
This code operates the same at runtime, as the original code from Cullen’s example. The only difference is in the formatting of the code that I’ve used, and in making the implicit variable hoisting explicitly known in the code.
A Matter Of Preference?
I think the variable declaration bit is somewhat a matter of preference. Personally, I don’t declare all my variables at the top of a function (with a few exceptions where I do… but I’m not sure I can explain my exceptions, logically :P)
If you are working on a team that understands variable scope correctly, it shouldn’t matter too much where the variables are declared.
If you’re working with people that are new(ish) to JavaScript or may not have a complete understanding of all these nuances, then putting the variables first can help to cut down on confusion – or at least spark a conversion to help them understand what’s going on.
Hopefully this will all change in the near future, though, as browsers and NodeJS all begin to standardize on the next version of JavaScript: ES6.
ES6: Block Scope w/ Let
In the near-future, JavaScript will have a more traditional “block scope” that respects the curly braces. ES6 is introducing the let
keyword to do this without breaking backward compatibility with existing JavaScript code.
It has been recommended by some, that we all use let
once it becomes standard. Until ES6 comes around, though, be sure to watch your variable declarations.
If you’d like to see the ES6 code in action, check out my short video on using ES6 “let” with IO.js.
Mastering JavaScript’s Oddities
If you’re interested in getting to know JavaScript’s oddities and quirks, and really leveling up your skills with the web’s most important language, check out these resources:
- My JavaScript Fundamentals screencast series from WatchMeCode (3 hours of screencasts for $64)
- My 5 Rules for Mastering JavaScript’s “this” – a free, 5 day email course
- My eBook version of 5 Rules for Mastering “this” ($5)
- Dhananjay Kumar’s Hoisting in JavaScript example
- A more in-depth JavaScript Scoping and Hoisting article from Ben Cherry