In his article on let
and const
Jason Orendorff states the following:
Crunchy performance details: In most cases, you can tell whether the declaration has run or not just by looking at the code, so the JavaScript engine does not actually need to perform an extra check every time the variable is accessed to make sure it’s been initialized. However, inside a closure, it sometimes isn’t clear. In those cases the JavaScript engine will do a run-time check. That means
let
can be a touch slower thanvar
.
I decided to try and find an example where this held true and was stumped.
For example, let us look at the following torture scenario:
function doSomethingDumb(q) {
function crash() { ++x; }
q.fn = crash;
crash();
let x;
return crash;
}
Even though the closure is returned at the end of the function, it is guaranteed that the return statement will never execute, even though x
is assigned to a member of q
(and thus may escape into the wild) x
will never be initialized and thus crash
will always crash.
In what case would it be impossible to tell whether the variable had been initialized?
Just put that into a condition that is only sometimes fulfilled:
function example() {
if (Math.random() < 0.33) tryIt();
const x = 5;
if (Math.random() < 0.5) tryIt();
function tryIt() {
console.log(x);
}
}
In this example I've chosen a random, but it could as well depend on the function's input parameters. In general, it is not statically decidable whether the statement that accesses the variable will be executed before the initialisation - that's the halting problem. You can write a sophisticated analyser that can determine this for many cases, but there's always a trade off between sophistication and overhead of the analyser.