Please type "I already searched for this issue":
I already searched for this issue.
Edition: (1st or 2nd)
2nd
Book Title:
Scope & Closures
Chapter:
Chapter 6: Limiting Scope Exposure
Section Title:
Scoping with Blocks
Problem:
The
{ .. }
curly-brace pair on aswitch
statement (around the set ofcase
clauses) does not define a block/scope.
As best I can tell, the switch statement curly-braces referred to do create a scope with const
or let
.
For example, with var
, foo outputs 'foo'
as expected.
switch (true) {
case true:
var foo = 'foo';
}
console.log(foo);
However, with let
, logging foo
produces a reference error. (Not expected if these braces aren't creating a scope)
switch (true) {
case true:
let foo = 'foo';
}
console.log(foo);
This came up in our last online Code Club discussion (which I believe you have visited previously). Thanks so much for providing this resource!
The cited quote is asserting that the outer pair of { .. }
attached to the switch
itself does not create a scope. A let
/ const
declaration in a case
clause block-scopes the declaration to that case
clause specifically, but the outer switch
statement itself is still not a block of scope.
If there are no { .. }
surrounding the case
clause's list of statements, then this list of statements itself acts like a block-scope (though not technically a block).
IOW, this is not a block-scope (and also not syntactically allowed):
switch (true) {
// not block scoped to the switch (but also syntactically disallowed)
let foo = 42;
console.log(foo);
}
But this is a block-scope:
switch (true) {
case true:
// the scope here is the `case` clause, specifically its statement list, even
// without any explicit { }
let foo = 42;
console.log(foo);
}
If case statements implicitly create a scope, I'd expect this to produce a reference error (via fallthrough):
switch (true) {
case true:
let foo = 42;
case 'anyvalue':
console.log(foo);
}
Unexpectedly however, it ouputs 42
. (Which unfortunately doesn't satisfy my ultimate questions of life, the universe, and everything in this case :laughing:)
Welp... I'm stumped. That's not what I understood.
According to the spec, the { }
around the case
statements are not a block -- well, sorta, it's a special CaseBlock
entity -- and the parsed AST does not have a "block" element for this node... but nevertheless a scope is created. So I was both correct and incorrect in the same sentence. Bonkers that TC39 chose to make that nuance. Shrugs. Definitely don't ever do that in a program, it's a terrible idea for confusion sake.
Ok. Appreciate you taking the time to look into this. Thanks again for all your work on the book and for making it available online! If you ever have time to join us again some time let us know!
@getify this project seems like fun. I want to contribute. How do i go about that? The documentation is not quite self sufficient
@KarenEfereyan This isn't really a "project" per se. It's a series of books I wrote (and am writing). Contributors are primarily those who find typos that my copyeditor may have missed, or occasionally find technical mistakes (such as this thread).
As for contributing in that capacity, see these guidelines.
If case statements implicitly create a scope, I'd expect this to produce a reference error (via fallthrough):
switch (true) { case true: let foo = 42; case 'anyvalue': console.log(foo); }
Unexpectedly however, it ouputs
42
. (Which unfortunately doesn't satisfy my ultimate questions of life, the universe, and everything in this case :laughing:)
Switch is a structural directive which natively defines how it handles execution - matched cases should execute. The case items themselves should be seen as they are all in one scope. This means each case acts like a piece of code that will execute when the it case matches the switch clause, all cases are in a transient scope under the switch directive, so ideally the switch can be called a block and not a scope.
The case items themselves should be seen as they are all in one scope.
This isn't entirely true, since if you put { .. }
around the statements of a single case clause, that is a nested block-scope.
@KarenEfereyan This isn't really a "project" per se. It's a series of books I wrote (and am writing). Contributors are primarily those who find typos that my copyeditor may have missed, or occasionally find technical mistakes (such as this thread).
As for contributing in that capacity, see these guidelines.
Okay thanks
The case items themselves should be seen as they are all in one scope.
This isn't entirely true, since if you put
{ .. }
around the statements of a single case clause, that _is_ a nested block-scope.
I understand it is scope when you put {...} around the statements. But the whole list of cases acts as if they are in one scope inside the switch when the case bodies are one-liner expressions as commented by @ericmathison
switch (true) {
case true:
let foo = 42;
case 'anyvalue':
console.log(foo);
}
Outputs 42
But when we put them in curly braces, scoping rules is effected:
switch (true) {
case true:
{ let foo = 42; }
case 'anyvalue':
{ console.log(foo); }
}
Throws an error
Uncaught ReferenceError: foo is not defined
Most helpful comment
If case statements implicitly create a scope, I'd expect this to produce a reference error (via fallthrough):
Unexpectedly however, it ouputs
42
. (Which unfortunately doesn't satisfy my ultimate questions of life, the universe, and everything in this case :laughing:)