And how ‘ solves a common JavaScript “gotcha”… let’ I’ve been writing JavaScript using the ES2015 (ES6) syntax for awhile now and have grown to appreciate many of the language changes for their elegance and simplicity. One of the first and easiest changes I adapted to was using / instead of . However, I took for granted the benefit provides over ; it isn’t just a flashy new syntax for , but rather provides an important scoping mechanism. let const var let var var I took for granted the benefit provides over let var... It’s worth noting first that instead of / . This is because will throw an error if an attempt is made to change its value after it has been declared, a useful feature to prevent accidental mutation. However, a mutable variable is often needed, particularly as a counter in looping scenarios. But why should you use instead of for these situations, if they both provide the basic mutability required of them? the vast majority of variables I declare are best suited for using _const_ let var const let var The simple answer is that that is absent in the function-scoped . This explanation obviously begs a practical example. Allow me to demonstrate this important distinction using a classic front-end engineering interview question: **let** provides block-scoping var In this example, what will be printed in the console? var callbacks = [];(function() {for (var i = 0; i < 5; i++) {callbacks.push( function() { return i; } );}})(); console.log(callbacks.map( function(cb) { return cb(); } )); In this example, we loop 5 times, each time pushing a function into the array. After the array is filled with 5 functions, we run each of them, logging their result to the console. A novice engineer might answer (incorrectly) that the result is , . callback [0, 1, 2, 3, 4] a reasonable analysis, but one that falls victim to the JavaScript “hoisting” gotcha Don’t be a victim. Avoid the hoisting trap with ‘let’! The correct answer is actually , and makes sense when you consider what hoisting does behind the scenes: [5, 5, 5, 5, 5] var callbacks = [];(function() { for ( = 0; i < 5; i++) {callbacks.push( function() { return i; } );}})(); var i; i console.log(callbacks.map( function(cb) { return cb(); } )); Notice how JavaScript hoists the variable declaration to the top of the function block, causing the value of to be by the time each of the callback functions have executed, since the loop has incremented completely before any of these functions are called. i 5 for There are a number of ways to classically solve this problem and get the script to log to the console, but gives us a very simple solution: [0, 1, 2, 3, 4] let var callbacks = [];(function() {for ( i = 0; i < 5; i++) {callbacks.push( function() { return i; } );}})(); let console.log(callbacks.map( function(cb) { return cb(); } )); That’s it — and the example works as expected! This is thanks to the block-scoping behavior of . Rather than being hoisted to the top of the function’s scope, , causing a separate instance of for each iteration. just replace **var** with **let** let _let_ stays in the block scope of the loop i So, should you ever use ? As you have likely gathered from the title of this article, I am of the opinion that . Technically, is still useful in situations where you want to maintain function scope instead of block scope, but I am of the firm belief that if you need to rely on an unintuitive hoist to get your script to work, you have bigger problems 😜. var you should never use **var** var In response to two of the most common points of discussion readers are bringing up: Update: It is true that isn’t immutable. For instance: const truly const myNotQuiteImmutableObject = {thisCanBeChanged: "not immutable"}; myNotQuiteImmutableObject.thisCanBeChanged = "see I changed it."; However, this still prevents basic mutation like: const immutableString = "you can't change me"; immutableString = "D'OH!"; // error If you need real immutability, check out Facebook’s excellent library. Immutable 2. “ isn’t supported in .” This is true, and even . This has an obvious and easy solution: Use . Babel will allow you to use all the best and latest features of JavaScript and then transpile into a vocabulary that even simple old IE8 can understand (with some exceptions). let {mySuperAncientBrowser} somewhat recent browsers still don’t have support for [let](http://caniuse.com/#feat=let) Babel