Какова точная семантика функций уровня блока в ES6?

Я пытаюсь обдумать новые стандартизированные функции уровня блоков в ES6, читая необработанные спецификации. Мое поверхностное понимание было:

  • Объявления функций уровня блока разрешены в ES6.
  • Они поднимаются на вершину квартала.
  • В строгом режиме они не видны за пределами содержащего блока.

Однако это еще более осложняется тем фактом, что часть этой семантики определена как "необязательная" и обязательная только для веб-браузеров ( Приложение B). Поэтому я хотел бы заполнить следующую таблицу:

                                             | Видимо за пределами блока?  | Водрузили? До какой точки?  |   "Протяжен"? |
------------------------------------------------------------------------------------------------------------------------
| Нестрогий режим, без "веб-расширений" | | | |
| Строгий режим, без "веб-расширений" | | | |
| Нестрогий режим, с "веб-расширениями" |
| Строгий режим с "веб-расширениями" | | | |

Также мне неясно, что означает "строгий режим" в этом контексте. Это различие, по-видимому, введено в Приложении B3.3 как часть некоторых дополнительных шагов для выполнения во время выполнения объявления функции:

1. If strict is false, then
...

Однако, насколько я вижу, strict относится к [[Strict]] внутренний слот объекта функции. Означает ли это, что:

// Non-strict surrounding code

{
    function foo() {"use strict";}
}

следует считать "строгим режимом" в таблице выше? Однако это противоречит моей первоначальной интуиции.

Пожалуйста, имейте в виду, что меня больше всего интересует сама спецификация ES6, независимо от фактических несоответствий в реализации.

2 ответа

Решение

Насколько я вижу, strict относится к [[Strict]] внутренний слот объекта функции.

И да. Это относится к строгости функции ( или скрипта), в которой происходит блок, содержащий объявление функции. Не в строгости функции, которая должна (или не должна) быть объявлена.

"Веб-расширения" применимы только к небрежному (нестрогому) коду и только в том случае, если внешний вид оператора функции "нормальный", то есть, например, если его имя не совпадает с формальным параметром или лексически объявленная переменная.

Обратите внимание, что нет никакой разницы между строгим и небрежным кодом без семантики веб-совместимости. В чистом ES6 только одно поведение для объявлений функций в блоках.

Таким образом, мы в основном имеем

                 |      web-compat               pure
-----------------+---------------------------------------------
strict mode ES6  |  block hoisting            block hoisting
sloppy mode ES6  |  it's complicated ¹        block hoisting
strict mode ES5  |  undefined behavior ²      SyntaxError
sloppy mode ES5  |  undefined behavior ³      SyntaxError

1: смотри ниже. Предупреждения запрашиваются.
2: Как правило, SyntaxError брошен
3: примечание в ES5.1 §12 говорит о " значительных и непримиримых вариациях среди реализаций " (таких как эти). Предупреждения рекомендуются.

Так как же теперь реализация ES6 с веб-совместимостью ведет себя для объявления функции в блоке в функции с неаккуратным режимом с устаревшей семантикой?
Прежде всего, чистая семантика все еще применяется. То есть объявление функции поднимается до верха лексического блока.
Тем не менее, есть также var объявление, которое поднимается на вершину вмещающей функции.
И когда объявление функции оценивается (в блоке, как если бы оно было встречено как инструкция), объект функции присваивается этой переменной области действия.

Это лучше объяснить с помощью кода:

function enclosing(…) {
    …
    {
         …
         function compat(…) { … }
         …
    }
    …
}

работает так же, как

function enclosing(…) {
    var compat₀ = undefined; // function-scoped
    …
    {
         let compat₁ = function compat(…) { … }; // block-scoped
         …
         compat₀ = compat₁;
         …
    }
    …
}

Да, это немного сбивает с толку, имея две разные привязки (обозначенные индексами 0 и 1) с одним и тем же именем. Теперь я могу кратко ответить на ваши вопросы:

Видимо за пределами блока?

Да вроде как var, Однако есть вторая привязка, которая видна только внутри блока.

Водрузили?

Да - дважды.

До какой точки?

Оба к функции (однако инициализируется с undefined) и блок (инициализируется с помощью объекта функции).

"Протяжен"?

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

Я не уверен, откуда твое замешательство. Согласно 10.2.1 очень ясно, что находится или не находится "в строгом режиме". В вашем образце foos [[Strict]] внутренний слот будет true Действительно и будет в строгом режиме, но блокировать хостинг у него не будет. Первое предложение (которое вы цитировали) относится к блоку хостинга, а не к контенту, сгенерированному в нем. Блок в вашем фрагменте не находится в строгом режиме, и, следовательно, этот раздел относится к нему.

Другие вопросы по тегам