Consider this ES2015 module and the behavior when run in node v4.4.5.
'use strict'
const outer = 1
switch ('foo') {
case 'bar':
const heyBar = 'HEY_BAR'
break
case 'baz':
const heyBaz = 'HEY_BAZ'
break
default:
const heyDefault = 'HEY_DEFAULT'
}
console.log(
outer, // 1, makes sense, same top-level scope
heyBar, // undefined. huh? I thought switch did NOT create a child scope
heyBaz, // undefined. huh? I thought switch did NOT create a child scope
heyDefault) // 'HEY_DEFAULT' makes sense
This seems internally inconsistent to me. If the switch statement did NOT create a lexical scope, I would expect all the hey*
variables to be part of the main scope and to all behave consistently. If the switch statement did create a lexical scope, I would still expect them to be consistent, but the variables declared in the case
clauses behave like they are in a child scope, whereas the variables in the default
clause behaves like it is in the outer scope.
My question is are there any child scopes involved in a switch statement, and if so what are the details of how they behave?
In node v6.4.0, the behavior is different. It looks like the switch block does indeed create a child block scope.
ReferenceError: heyBar is not defined
And that seems a lot more straightforward to understand.
I can't reproduce your behavior at all. I immediately get a ReferenceError
(Node 6.4.0 and current Firefox for that matter):
ReferenceError: heyBar is not defined
Which seems like the correct behavior to me. AFAIK switch
statements with brackets DO create a block, and thus a lexical scope for block-scoped entities. The case
statements themselves do not create their own blocks.
If we expand this example with a foo
case in the switch
statement, it throws a ReferenceError
as well:
'use strict'
const outer = 1
switch ('foo') {
case 'bar':
const heyBar = 'HEY_BAR'
break
case 'baz':
const heyBaz = 'HEY_BAZ'
break
case 'foo':
const heyFoo = 'HEY_FOO'
break
default:
const heyDefault = 'HEY_DEFAULT'
}
console.log(
outer,
heyFoo,
heyBar,
heyBaz,
heyDefault) // ReferenceError: heyFoo is not defined
Reference
Here is the section in the spec: 13.12.11 Runtime Semantics: Evaluation
5. Let blockEnv be NewDeclarativeEnvironment(oldEnv).
6. Perform BlockDeclarationInstantiation(CaseBlock, blockEnv).
Where CaseBlock
is the block statement of the switch case.
This roughly translates to:
Create a new block environment in the block of the switch statement (switch { <-here-> }
) and instantiate all block level declarations (such as let
, const
or block level function declarations).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With