2

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 than var.

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?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
JeremiahB
  • 896
  • 8
  • 15

2 Answers2

3

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.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • @BekimBacaj The question was "*Here's an example, and it's quite clear whether `x` is initialised or not when accessed; what is a case where that is not clear?*", and I've shown an example where it's not so easy to see and that it is cannot be determined in every case. – Bergi Apr 11 '17 at 01:20
0

There is no such thing as slow or fast handle, i.e.: named value, be it a var a const or a let. There's no such thing as "unable to determine" if they are initialized either. Moreover let/s don't get initialized - they simply get assigned. And since they are made to act similar to 'undeclared variables' they will be assigned their value at runtime and exactly at their point declaration.

Therefore, if a stop error happens occur just one line above the let declaration. It will remain fully undeclared. An you will know it just by looking at the code.

Bekim Bacaj
  • 5,707
  • 2
  • 24
  • 26
  • You might want to take a look at [this](http://stackoverflow.com/q/31219420/1048572) for what "declaration" and "initialisation" mean for `let`/`const`. – Bergi Apr 11 '17 at 01:25
  • Hm, they don't behave similar to undeclared variables at all imo. And yes, while it is always possible for the interpreter to determine (test) whether the variable is already initialised or not, we are talking about the compiler optimisation that determines whether such a test is necessary or not. Which is not decidable. – Bergi Apr 11 '17 at 01:31
  • There's a bug \ wrong implementation and a wrong behavior of varletconst in a conditional \ block \ local scope obstructing the look-up principle after a failed look-around as in: `function lookupDisabled(){ const myval = 1; console.log( myval ); if(myval === 1) { /*console.log( myval ); ReferenceError*/ const myval = 2; console.log( myval ); if( myval === 2 ){ /*console.log( myval ); ReferenceError*/ const myval = 3; console.log( myval );} console.log( myval ); } return myval; }` where the commented logs of myval should be able to look-up in the outerscope an log 1. – Bekim Bacaj Apr 11 '17 at 04:09
  • 1
    No, this is neither a bug nor wrong. Please check [my answer](http://stackoverflow.com/q/31219420/1048572) for how this works. And [it's very much on purpose](http://stackoverflow.com/q/42718257/1048572). – Bergi Apr 11 '17 at 10:02
  • Any counterintuitive, unexpected, therefore wrong behavior; especially the ones that go against a fundamental programming principle of a given language is by definition and in general considered a bug. This one is breaking the **look-up principle** without a reason. This is a premature & wrong look-ahead inclusion optimization at parse time (which might spare a few cpu cycles), but nonetheless, a bug. Just because the identifier of a given value is waiting to be declared, should not be a reason to make it unreachable, especially not when a conditional creating the current context says !0. – Bekim Bacaj Apr 11 '17 at 12:18
  • It's not breaking any lookup-principle. You just have to understand that scopes are introduced by *blocks*, not by variable declarations. – Bergi Apr 11 '17 at 12:32