38

Consider the file sample.es6

switch (1) {
    case 1:
        const foo = 1;
        break;
    case 2:
        const foo = 2;
        break;
}

If I run it with Node I got

$ node --version
v4.2.11
$ node sample.es6 
/tmp/sample.es6:6
const foo = 2;
^

SyntaxError: Identifier 'foo' has already been declared
    at Object.<anonymous> (/tmp/sample.es6:1:11)
    at Module._compile (module.js:435:26)
    at Object.Module._extensions..js (module.js:442:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:311:12)
    at Function.Module.runMain (module.js:467:10)
    at startup (node.js:134:18)
    at node.js:961:3

Why I'm getting this error? Node shouldn't evaluate const foo = 2;.

Raniere Silva
  • 2,527
  • 1
  • 18
  • 34
  • 2
    What are you trying to do after all? Where do you want to use `foo`? – Bergi Oct 28 '15 at 17:58
  • Are you confused about `const` in general, or why it throws an error when they are in separate `case` sections? – loganfsmyth Oct 28 '15 at 18:50
  • This was the minimal example that I could provide. I will pass `foo` to functions. Why it throws an error when they are in separate case sections. – Raniere Silva Oct 28 '15 at 23:02
  • 3
    @RaniereSilva: A `case` section doesn't have it's own scope, so multiple declarations of `foo` in them will collide with each other. You can wrap them in blocks (`{ … }`) though to solve this. – Bergi Oct 29 '15 at 00:03

5 Answers5

81

You can create scope blocks around your cases, and the compiler will be happy:

switch (1) {
    case 1: {
        // notice these extra curly braces
        const foo = 1;
        break;
    }
    case 2: {
        const foo = 2;
        break;
    }
}

Read the answer from Igor if you need more context.

Hinrich
  • 13,485
  • 7
  • 43
  • 66
21

You are getting a SyntaxError because you are re-declaring a variable in the same scope; a switch statement contains only one underlying block, rather than one block per case.

JavaScript throws the error at compile time. "Node shouldn't evaluate const foo = 2;" is irrelevant because this error occurs before Node evaluates anything.

One purpose of const (and a lot of new ES6 features, for example the new module spec) is to enable the compiler to do some static analysis. const tells the compiler that the variable will never be reassigned, which allows the engine to handle it more efficiently.

Of course, this requires a compile-time check to make sure the variable is indeed never reassigned (or redeclared), which is why you are seeing the error.

Igor Raush
  • 15,080
  • 1
  • 34
  • 55
  • 2
    That's one point of `const`. Another one is to prevent me from clobbering my own variables. –  Oct 28 '15 at 17:41
  • 5
    Maybe worth mentioning that there is only one underlying block in the switch statement. One might guess that there's a block scope per case, which is not... the case. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let – Christiaan Westerbeek Jul 08 '16 at 09:02
  • 1
    @Christiaan, thanks, I have added this clarification (albeit much later than you pointed it out). – Igor Raush Mar 22 '17 at 17:29
8

You can use Immediately Invoked Function Expression (IIFE) for const assignment:

const foo=(function(){
  switch (1) {
    case 1:
      return 1;
      break;
    case 2:
      return 2;
      break;
  }
})();

console.log('foo = '+foo); /* foo = 1 */

Altenatively, you can create a scope inside the case with curly braces, but you cannot access the foo outside switch block :

switch (1) {
  case 1: {
    const foo = 1;
    console.log(foo+' from inside'); /* 1 from inside */
  } break;
  case 2: {
    const foo = 2;
    console.log(foo+' from inside');
  } break;
}

console.log(foo+' from outside'); /* foo is not defined */
Fatma Nabilla
  • 1,301
  • 1
  • 9
  • 8
1

If you'are expecting to create a scope inside case statement you should use (IIFE) Immediately Invoked Function Expression. It will allow you to create additional scope that you need inside case statement.

function (value) {
   switch (value) {
     case 1:
       return (function() {
         const foo = 1
         return foo
       }())
       break;
     case 2:
       return (function() {
         const foo = 2
         return foo
       }())
       break;
   }
}

Here is an example https://jsfiddle.net/hermanleus/e4ceq7xt/2/

Hope it helps

0

Use a temporary variable to determine the value and then set the constant after the value has been determined.

let bar;
switch (1) {
    case 1:
        bar = 1;
        break;
    case 2:
        bar = 2;
        break;
}
const foo = bar;
bgoerdt
  • 162
  • 1
  • 7