Reputation: 312
The following lines of JavaScript
try {
function _free() {}
var _free = 1;
} finally { }
result in the following error:
Uncaught SyntaxError: Identifier '_free' has already been declared
However, the following two blocks of JavaScript code don't:
Without the try
block scope:
function _free() {}
var _free = 1;
Within a function
scope:
function a() {
function _free() {}
var _free = 1;
}
But why?
(Testing environment: Chromium 61.0.3126.0)
Upvotes: 17
Views: 1437
Reputation: 3331
To expand on Bergis answer, there is a difference in how the code is interpreted in ES5 and ES6 since block-scoped function declarations were added.
Input:
function test() {
try {
function _free() { }
var _free = 1;
} finally { }
}
Since ES5 does not support block-level functions, _free
is hoisted to the parent function:
function test() {
var _free = function _free() { }
try {
var _free = 1;
} finally { }
}
In ES6, the function is declared at block-level, and semantically equal to a let
/const
declaration:
function test() {
try {
let _free = function _free() { }
var _free = 1;
} finally { }
}
This throws an error because var _free
tries to declare a variable which is already declared.
For example, this throws in ES6 as well:
let _free;
var _free = 1; // SyntaxError: Indentifier '_free' has already been declared
While this is fine:
var _free;
var _free = 1; // No SyntaxError
Setting the value of the already declared identifier is fine:
let _free;
_free = 1;
Therefore, to set the declared identifier _free
to 1, you need to skip the second declaration:
try {
function _free() { }
_free = 1;
} finally { }
Upvotes: 5
Reputation: 664454
Because block-scoped function declarations are a new ES6 feature and were made safe (i.e. throw an error on name collisions, similar to let
and const
), but the other cases (which are programmer mistakes regardless) needed to stay backwards compatible and silently overwrite the function.
Upvotes: 15