Block scopes not associated with a function or control flow statement, huh? Seems counterintuitive that making a variable not accessible would help in some way, doesn’t it? But from time to time a good reason to do this will come up. Consider this code:
let request;
{
const input = getInput();
const helper = new Helper();
request = helper.fixUp(input);
helper.retire();
}
// do stuff with request
Suppose there are good reasons to prevent later code from accidentally using input
and helper
. Let’s say input
is in some weird raw form with subtle differences that the codebase (other than fixUp
) can’t handle correctly. And that retire
puts helper
into some state where it can’t be used anymore.
In this case, it’s better to have these go out of scope right away and to put most of the code outside that block where it can’t accidentally use them. If the code were to try to reference input
or helper
, you’d get a reference error right away instead of having to run to some point where little differences between input
and request
cause something to happen or for a later use of helper
to give wrong results.
There are other ways to address this kind of problem. One thing is to name things more descriptively, e.g. inputRawDontUse
. Another appealing option is to move that block into a function, which is especially nice if it’s self contained and otherwise makes sense as a single, more abstract step.
Other languages have features like this too. Here are some additional thoughts specific to JavaScript. JavaScript is garbage collected, so when your program is done with an object like helper
above, the language runtime cleans it up for you, but not at any specific in the code. Other languages make stronger promises that an object like helper
will be ‘destroyed’ exactly at when control leaves the block, and you can customize the ‘destructor’ to run some custom piece of code. It’s less error prone to write this (pseudocode):
class ManagedHelper {
destructor() { this.retire(); }
}
...
{
const a = new ManagedHelper();
// use a
}
than to need explicit cleanup everywhere it’s used:
class Helper {
retire() { ... }
}
...
const a = new Helper();
try {
// use a
} finally {
a.retire();
}
Also, JavaScript won’t allow you to assign a const separate from declaring it, so you coudn’t write this:
const result;
{
// bunch of stuff leading up
result = computation.getAnswer();
}
You’d have to declare it as let result;
, which would give the false impression that you’re welcoming reassignment even if you aren’t. Some languages let you do this, and using these blocks is much nicer.