Страницы

Поиск по вопросам

среда, 26 февраля 2020 г.

Объявление функции в if и ее подъем

#javascript


В книге по js написано 


  Определения функции могут находиться только в коде верхнего уровня или быть вложенными
в объявления других функций. Они не могут находиться внутри инструкций if, циклов while
или любых других инструкций


Код у меня такой



console.log(fun);

if (true) {
  console.log(fun(4));
 
  function fun(a) {
    return a + a;
  };

  console.log(fun(5));
}

console.log(fun(6));






"use strict";

console.log(fun);

if (true) {
  console.log(fun(4));
 
  function fun(a) {
    return a + a;
  };

  console.log(fun(5));
}

console.log(fun(6));




Так вот, почему не генерируется исключение из за определения функции в if? И почему
подъем происходит лишь в начало блока if (ведь в js нет области видимости блока), а
не в начало сценария? И почему в начале сценария(т.е до if) fun уже объявлена, но без
инициализации(возвращает undefined)?

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


Ответы

Ответ 1



TL;DR; если функция используется снаружи блока - она ведет себя как переменная объявленная с помощью var, внутри блока - как обычно Действительно, нахождение определений функций в StatementList, который входит в Block. Подробно это описывается в спецификации, в секции B.3.3 До ECMAScript 2015, спецификация не определяла FunctionDeclaration как возможный элемент StatementList в Block. Однако, поддержка этой формы FunctionDeclaration была допустимым расширением и многие браузерные реализации ECMAScript разрешали это. К сожалению, семантика таких определений отличается в разных реализациях. Из-за этих семантических различий, существующий браузерный ECMAScript код, который использует определения функций на уровне Block, переносим только среди браузерных реализаций, если использование зависит от семантического пересечения всех браузерных реализаций для таких определений. Ниже приведены случаи попадающие в такое пересечение: На функцию, определенную в блоке, есть ссылки только в этом блоке Одна или более FunctionDeclaration, у которой BindgingIndentifier является имя f встречающейся в коде содержащей функции g и это определение вложено в блок В коде функции g нет других определений f, которые не использовали бы var Все вхождения f в качестве IdentifierReference находятся внутри StatementList того блока, в котором находится определение f Функция определена и, возможно, используется внутри одного блока, но также на нее ссылаются определения внутри функции, которые находятся не в этом же блоке. Одна или более FunctionDeclaration, у которой BindgingIndentifier является имя f встречающейся в коде содержащей функции g и это определение вложено в блок В коде функции g нет других определений f, которые не использовали бы var Могут быть вхождения f в качестве IdentifierReference находящиеся внутри StatementList того блока, в котором находится определение f Хотя бы одно вхождение f в качестве IdentifierReference внутри другой функции h, которая так же вложена в g, и нет других определений f перекрывающих ссылку на f внутри h Все вызовы h происходят после того, как определение f будет выполнено. Функция определена и, возможно, используется внутри одного блока, но также на нее есть ссылки в следующих блоках. Одна или более FunctionDeclaration, у которой BindgingIndentifier является имя f встречающейся в коде содержащей функции g и это определение вложено в блок В коде функции g нет других определений f, которые не использовали бы var Могут быть вхождения f в качестве IdentifierReference находящиеся внутри StatementList того блока, в котором находится определение f Есть хотя бы одно вхождение f в качестве IdentifierReference внутри кода функции g, который лексически следует за блоком, в котором определеная функция f. Первый вариант совместим с семантикой определения функций на уровне блока, добавленной в ECMAScript 2015. Любой ранее существующий код, который использует данный вариант будет работать так, как это описано в главах 9, 13 и 14 этой спецификации. Для совместимости второго и третьего необходимо расширение семантики в главах 9, 14, 18.2.1, и 15.1.11. Далее в спецификации приведены изменения для нужных глав. Можно рассмотреть изменение алгоритма FunctionDeclarationInstantiation, которое приведено в пункте B.3.3.1. А именно добавление дополнительных шагов: в случае не strictидет попытка заменить все FunctionDeclaration, находящиеся внутри блоков, либо CaseClause, либо DefaultClause на VariableStatement и в случае невозможности - показывается ошибка. Соответственно, если ошибок не было, вне блока будет поведение аналогичное объявлению var.

Ответ 2



Es6 ввёл блочную область видимости функций https://github.com/azat-io/you-dont-know-js-ru/blob/master/es6%20%26%20beyond/ch2.md Книга старая и не учитывает новый стандарт Для ошибки 'use strict'

Комментариев нет:

Отправить комментарий