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.