Doug Crockford discusses let
at this point in his talk, "The Better Parts".
The point is, let
avoids a source of misunderstanding, esp. for programmers with expectations set by languages with block-scope. A var
has function scope (it declares a variable that's visible throughout the function) even though it looks like it has block scope.
var
might possibly still be useful in an extreme case like machine-generated code, but I'm stretching hard there.
(const
is also new and has block scope. After let x = {'hi': 'SE'}
you can reassign to x
, while after const y = x
you cannot reassign to y
. That's often preferrable since it keeps something from accidentally changing out from under you. But to be clear, you can still modify the object y.hi = 'SO'
unless you freeze it.)
Realistically, your impression is right on for ES6: Adopt let
and const
. Stop using var
.
(In another performance of "The Better Parts", Doug says why ===
was added rather than fixing the problems of ==
. ==
produces some "surprising" results, so just adopt ===
.)
A Revealing Example
Mozilla Developer Network gives an example where var
does not work as intended. Their example is a realistic one that sets onclick
handlers in a web page. Here's a smaller test case:
var a = [];
(function () {
'use strict';
for (let i = 0; i < 5; ++i) { // *** `let` works as expected ***
a.push( function() {return i;} );
}
} ());
console.log(a.map( function(f) {return f();} ));
// prints [0, 1, 2, 3, 4]
// Start over, but change `let` to `var`.
// prints [5, 5, 5, 5, 5]
var
trips us up because all loop iterations share the same function-scoped i
variable, which has the value 5
after the loop finishes.
Another Telling Example
function f(x) {
let y = 1;
if (x > 0) {
let y = 2; // `let` declares a variable in this block
}
return y;
}
[f(1), f(-1)] // --> [1, 1]
// Start over, but change `let` to `var`.
// --> [2, 1]
let
declares block-scoped variables.
var
confuses us by referring to the same variable throughout the function.
var
as a conscious indicator that this variable is intended to be scoped to the entire function might be a useful "self-documenting" convention.let
statement right at the top of a function, I think it's just as obvious that you intended to scope it to the entire function. I don't think usingvar
makes it any clearer than simply locating it at the top.var
still exists, is backwards-compatibility. If it weren't for that, they'd have removedvar
altogether, or never introducedlet
in the first place, instead changing the semantics ofvar
to what it arguably should have been all along.var
seem thin to me, and not enough to warrant having a third kind of variable that jumps around. You can scope alet
to a whole function simply by placing it at the top of the function, which is much clearer in intent than writingvar
in a block (in order to have it hoisted out of that block so you can then use it outside the block - weird). He warns that if you scope alet
to a function then "it's just position that signals the difference, rather than syntax", but I think that's a good thing.var
. the examples he presents for keepingvar
seem contrived -- and are based on severe coding errors. It's much better to run into an error and be forced to fix such errors than to use language functions that let one get away with it! What's next, advise to wrap everything in an try/catch to prevent crashes? The rest of that link is good but I don't agree at all with that particular part.