6

If we declare a variable and a function with same name, it is accepting re-declaration. But when we do the same thing inside a block, it shows re-declaration error.
Code:

var x;
function x() {}; // no error.

But in this case i'm getting Error.

{
  var inside; // re-declaration error.
  function inside() {};
}

expected result should be no error.

0

2 Answers 2

5

This is an EcmaScript 6 change. From ES6 onwards it's no longer allowed to have duplicate bindings within a block scope.

The ES5 spec does not have such a restriction but in the ES6 spec the semantics have been changed:

13.2.1 Static Semantics: Early Errors

Block : { StatementList }

  • It is a Syntax Error if the LexicallyDeclaredNames of StatementList contains any duplicate entries.

  • It is a Syntax Error if any element of the LexicallyDeclaredNames of StatementList also occurs in the VarDeclaredNames of StatementList.

The first part is relevant - LexicallyDeclaredNames contains all declarations found within the code inside the block.

Presumably, this is part of a change in semantics function declarations in ES6, since now they can be block scoped:

{ //block 1
  function foo() { // declared in block 1
    return 1;
  }
  console.log("block 1: foo() === 1", foo() === 1);
  
  { // block 2
    function foo() { // declared in block 2
      return 2;
    }
    console.log("block 2: foo() === 2", foo() === 2);
  }
  
  console.log("block 1: foo() === 1", foo() === 1);
}

This is a syntactic sugar over this equivalent ES5 code:

(function() { //block 1
  var foo = function() {
    return 1;
  }
  console.log("block 1: foo() === 1", foo() === 1);
  (function() { //block 2
    var foo = function() {
      return 2;
    }
    console.log("block 2: foo() === 2", foo() === 2);
  })();
  console.log("block 1: foo() === 1", foo() === 1);
})();

However, this feature cannot work with duplicate names.

The same behaviour persists for any block, including other types of block statements. Here is an example:

{ //block
  function foo() { return 1; }
  console.log("block: foo() === 1", foo() === 1);
  
  if (true) { // if block
    function foo() { return 2; }
    console.log("if block: foo() === 2", foo() === 2);
  }
  
  for (var i = 0; i < 1; i++) { // for block
    function foo() { return 3; }
    console.log("for block: foo() === 3", foo() === 3);
  }
  
  switch ("hello world") { // case block
    default:
      function foo() { return 4; }
      console.log("case block: foo() === 4", foo() === 4);
  }
  
  console.log("block: foo() === 1", foo() === 1);
}

However, it should be noted that duplicate declaration of the same type (var or function) do not lead to an error:

{
  var foo = 1;
  var foo = 2;
  
  console.log("foo ->", foo);
}

{
  function bar() { return "a"; }
  function bar() { return "b"; }
  
  console.log("bar() ->", bar());
}

So, it seems like they aren't treated as different declarations but overwriting the same lexically declared name.

Sign up to request clarification or add additional context in comments.

1 Comment

"From ES6 onwards it's no longer allowed to have duplicate bindings within a block scope." Small nit: That gives the impression the rules changed, but the old rules didn't change for the old style of declaration (VarScopedDeclaration), as your last snippet shows. It's just that the new kind of declaration (LexicallyScopedDeclaration) doesn't allow duplication. So in the same block you can have multiple VarScopedDeclations for x, but you can't have multiple LexicallyScopedDeclarations for x, or a LexicallyScopedDeclaration and a VarScopedDeclation for x.
0

While exploring this further I came across this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError

The funny thing is that my result is different than theirs for this situation:

    try{
        eval(`{
            var x;
            function x(){};
        }`);
    }catch(e){
        console.log(e instanceof SyntaxError);
        console.log(e.message);                // "Hello"
        console.log(e.name);                   // "SyntaxError"
        console.log(e.fileName);               // "someFile.js"
        console.log(e.lineNumber);             // 10
        console.log(e.columnNumber);           // 0
        console.log(e.stack);                  // "@Scratchpad/2:11:9\n"
    }

Result:

true // instanceof SyntaxError
06:01:10.526 VM3194:22 Identifier 'x' has already been declared // e.message
06:01:10.527 VM3194:23 SyntaxError // e.name
06:01:10.527 VM3194:24 undefined   // e.filename
06:01:10.527 VM3194:25 undefined   // e.lineNumber
06:01:10.527 VM3194:26 undefined   // e.columnNumber
06:01:10.527 VM3194:27 SyntaxError: Identifier 'x' has already been declared at VM3194:16 // e.stack

1 Comment

console.log(Object.getOwnPropertyNames(e)); returns ["stack", "message"]. I guess that SyntaxError in my version of Chrome isn't the same...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.