If you examine the documentation for those exceptions you linked in your question, you can see the why, which I don't think has been addressed here.
A side note first: it bears mentioning that exceptions didn't exist in EMCAScript until edition 3. var obviously predates this language feature by a lot. why var and let are different is largely due to the fact that exceptions were available when let was introduced, and not when var was introduced. That history underlines all of this. 1999 was a busy year, also!
Anyway, into the gears. Look what happens here:
// example A
(function () {
console.log(somethingUndefined - 1);
var somethingUndefined;
console.log('another operation');
})();
An error, then the code plows on. Can we catch this and deal with it?
// example B
(function () {
try {
console.log(somethingUndefined - 1);
var somethingUndefined = 50;
console.log('another operation');
} catch (e) {
console.log('I want to deal with problems here');
return;
}
console.log('plowing on');
})();
Nope.
Behind the scenes, this code looks like this:
// example C
(function () {
var somethingUndefined = undefined;
try {
console.log(somethingUndefined - 1);
somethingUndefined = 50;
console.log('another operation');
} catch (e) {
console.log('I want to deal with problems here');
return;
}
console.log('plowing on');
})();
There is no "temporal dead zone" because there is no point in example B & C where the variable somethingUndefined
is not something. It's a typeof "undefined", somethingUndefined === undefined
, that's not nothing. Then it's 50, but too late to be useful. Useful or not, we can use it to do things because it has a value. Line 1, line 8, it always has some value. Compare the difference in output here:
// example D
(function () {
try {
console.log(somethingUndeclared - 1);
console.log('another operation');
} catch (e) {
console.log('I want to deal with problems here');
console.log(e);
}
})();
At every point in example D, somethingUndeclared
is nothing. It's an always dead zone. I am not sure which EMCAScript edition the above code began to throw exceptions, but it's less breaking for it to do so because this situation is always going to be an error.
Unless in some other part of the same scope OR the parent scopes somethingUndeclared
was defined, probably for some other purpose. Or maybe the code var somethingUndeclared;
is laying around somewhere in the scope or the parent scopes for some reason, so there's no exception thrown in anoy of the code above. That's the argument for using let or const almost exclusively.
When you use let or const, there is a "dead zone," a point in time when it isn't anything, then it will be something. It isn't undefined
, it's an exception waiting to happen. Until the let statement is reached, it acts like an undeclared variable, throwing an exception, then at the declaration line it acts like a var with a value. It is a blending of the behavior of var with the outcome of an undeclared variable.
// example D
(function () { // temporal dead zone, something is nothing
try { // temporal dead zone, something is nothing
console.log(something - 1); // exceptional behavior! temporal dead zone
let something = 50; // temporal live zone begins here!
console.log('another operation');
} catch (e) {
console.log('I want to deal with problems here'); // you could call this a dead zone
console.log(e); // dead
}
// dead
})(); // way dead
Which moves us on to the begged question, "why not pull off the bandaid, deal with the BC break for the sake of consistency in the language?" The answer to that is because good enough is usually good enough. There are millions of lines of javascript managing accordions and image galleries and other UI bells and whistles. One opts-in to a more mature set of language features when EMCAScript is filling mission-critical roles. Or you just don't like sloppy code for your sweet tab navigation. Consistency in the language is not worth breaking all of the code out there that is good enough to do what it needs to do most of the time. Imagine the mountains of good enough that have accumulated since it was even possible to throw an exception in this language ('99).
When we need it to do what it is supposed to do all of the time, we can harness these features. When it would be a catastrophe for undefined = 100;
to be in some file in the project, we can opt-in to exceptions. When the progressive enhancement fails and we get no tooltips, we have a less-nice UX than we'd hoped for. var and let have different histories and different weight on their shoulders, so they're likely to always act differently.