在ES2015中切换语句和范围

Pet*_*ons 4 javascript v8 node.js ecmascript-6

考虑此ES2015模块以及在节点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
Run Code Online (Sandbox Code Playgroud)

这似乎与我内部不一致.如果switch语句没有创建词法范围,我希望所有hey*变量都是主范围的一部分,并且所有变量都表现一致.如果switch语句确实创建了一个词法范围,我仍然希望它们是一致的,但是在case子句中声明的变量的行为就像它们在子范围内一样,而default子句中的变量的行为就像它在外部范围中一样.

我的问题是 switch语句中是否涉及任何子范围,如果是,那么它们的行为方式有哪些细节?

在节点v6.4.0中,行为是不同的.看起来切换块确实创建了子块范围.

ReferenceError: heyBar is not defined
Run Code Online (Sandbox Code Playgroud)

这似乎更容易理解.

nil*_*ils 9

我根本无法重现你的行为.我马上得到了一个ReferenceError(Node 6.4.0和当前的Firefox):

ReferenceError: heyBar is not defined
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎是正确的行为.switch带括号DO的AFAIK 语句创建一个块,因此是块范围实体的词法范围.该case语句本身并不创造自己的块.

如果我们fooswitch语句中使用case 扩展此示例,它ReferenceError也会抛出一个:

'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
Run Code Online (Sandbox Code Playgroud)

参考

以下是规范中的部分:13.12.11运行时语义:评估

5. Let blockEnv be NewDeclarativeEnvironment(oldEnv).
6. Perform BlockDeclarationInstantiation(CaseBlock, blockEnv).
Run Code Online (Sandbox Code Playgroud)

CaseBlock开关盒的块语句在哪里.

这大致意味着:

在switch语句(switch { <-here-> })的块中创建一个新的块环境,并实例化所有块级声明(例如let,const或块级函数声明).