Подтвердить что ты не робот

Почему переопределение идентификатора функции в блоке try вызывает синтаксис?

Следующие строки JavaScript

try {
    function _free() {}
    var _free = 1;
} finally { }

приводят к следующей ошибке:

 Uncaught SyntaxError: Identifier '_free' has already been declared

Однако следующие два блока кода JavaScript не имеют значения:

  • Без области try:

    function _free() {}
    var _free = 1;
    
  • В пределах function:

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

Но почему?

(среда тестирования: Chromium 61.0.3126.0)

4b9b3361

Ответ 1

Потому что объявления функций с блочным ограничением являются новой функцией ES6 и были сделаны безопасными (т.е. вывести ошибку при столкновении имен, аналогичную let и const), но другие случаи (которые являются ошибками программиста независимо) должны были оставаться обратно совместимыми и молча перезаписать функцию.

Ответ 2

Чтобы расширить на ответ Бергиса, есть разница в том, как код интерпретируется в ES5 и ES6, поскольку добавлены объявления функций с блочной областью.

Input:

function test() {
    try {
        function _free() { }
        var _free = 1;
    } finally { }
}

Так как ES5 не поддерживает функции уровня блока, _free поднял родительскую функцию:

function test() {
    var _free = function _free() { }
    try {
        var _free = 1;
    } finally { }
}

В ES6 функция объявляется на уровне блока и семантически равна объявлению let/const:

function test() {
    try {
        let _free = function _free() { }
        var _free = 1;
    } finally { }
}

Это вызывает ошибку, потому что var _free пытается объявить переменную, которая уже объявлена. Например, это также вызывает ES6:

let _free;
var _free = 1;    // SyntaxError: Indentifier '_free' has already been declared

Пока это нормально:

var _free;
var _free = 1;    // No SyntaxError

Установка значения уже объявленного идентификатора в порядке:

let _free;
_free = 1;

Поэтому, чтобы установить объявленный идентификатор _free в 1, вам нужно пропустить второе объявление:

try {
    function _free() { }
    _free = 1;
} finally { }