Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does redeclaring a function identifier within a try block throw a SyntaxError?

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:

  1. Without the try block scope:

    function _free() {}
    var _free = 1;
    
  2. Within a function scope:

    function a() {
        function _free() {}
        var _free = 1;
    }
    

But why?

(Testing environment: Chromium 61.0.3126.0)

like image 513
zhouhy Avatar asked Jul 04 '17 04:07

zhouhy


People also ask

Can We keep code in try block that will not throw exception?

So, it is recommended not to keeping the code in try block that will not throw an exception. Java try block must be followed by either catch or finally block. Java catch block is used to handle the Exception by declaring the type of exception within the parameter.

What is the purpose of a function try block in Java?

The primary purpose of function-try-blocks is to respond to an exception thrown from the member initializer list in a constructor by logging and rethrowing, modifying the exception object and rethrowing, throwing a different exception instead, or terminating the program.

Is it possible to declare a function inside a block?

Sure, but you didn't use var for the declaration of a in the block scope. You used a function declaration, which does respect block scopes (otherwise it would be completely invalid code, as in ES5 strict mode). Same applies here.

What does a try block look like in JavaScript?

In general, a try block looks like the following: try { code } catch and finally blocks . . . The segment in the example labeled code contains one or more legal lines of code that could throw an exception.


2 Answers

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.

like image 170
Bergi Avatar answered Oct 21 '22 06:10

Bergi


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 { }
like image 24
Leon Adler Avatar answered Oct 21 '22 06:10

Leon Adler