Невозможно перезаписать функцию изнутри функции

Я получил неожиданный результат. Здесь код:

b = function c() {
  console.log(c);
  c = 3;
  console.log(c);
}
b();

Ответ 1

Вы используете выражение функции :

Функция выражения:
Функция Идентификатор opt (FormalParameterList opt) {FunctionBody}

Итак, b = function c() { ... }; является абсолютно допустимым, строгим режимом или другим. То, что происходит с c, является другим вопросом. Согласно спецификациям:

Производство FunctionExpression: Идентификатор функции ( FormalParameterList opt) {FunctionBody}
оценивается следующим образом:

[...]
3. Назовите CreateImmutableBinding конкретный метод envRec передавая значение String идентификатора в качестве аргумента.
4. Пусть замыкание является результатом создания нового объекта Function как указано в 13.2 [...]
5. Вызовите метод InitializeImmutableBinding для envRec передавая значение String идентификатора и замыкание в качестве аргументов.
[...]

Примечание
Идентификатор в выражении Function можно ссылаться из внутри функции FunctionExpression FunctionBody, чтобы функция называть себя рекурсивно. Однако, в отличие от FunctionDeclaration, Идентификатор в выражении Function не может ссылаться и не влияет на область применения Expression.

Итак:

  • c отображается внутри функции, но не снаружи
  • c не может быть перезаписана внутри функции (обязательная привязка)

Между тем, из приведенного ниже кода я получил право "3".
function ff() {

Это объявление функции; здесь применяются различные (и более очевидные) правила.

Ответ 2

Вы не можете перезаписать функцию с именем variable внутри своего объявления. Имя NFE (Именованное выражение функции) не может быть перезаписано (поскольку оно является постоянным)

Это ясно, когда вы пишете в строгом режиме JS. Попробуйте пример ниже:

'use strict';

var b = function c(){
  console.log(c);
  c = 3; // c still is a function
  console.log(c);
}

b();

Ответ 3

Этот шаблон объявления функции, показанный в первом примере, называется NFE (с именем function expression), а другой называется объявлением функции. Большая разница в том, что в случае NFE имя функции i.e. c в нашем случае живет только в пределах области действия. Поэтому, если вы попытаетесь называть его своим именем извне, вы получите ошибку, c is not defined, что означает, что c не существует глобально.

b = function c(){
  console.log(c);
    c=3;
  console.log(c);
}
c(); //c is not defined

Теперь внимательно посмотрите на строку c=3 внутри тела функции c. Обычно этот блок кода должен был бы создать глобальную переменную именем c, вне тела функции, которое было бы доступно, вне функции. Но здесь, поскольку c уже живет внутри области действия собственного тела, он не позволит вам объявить там, потому что это будет означать перезаписать его собственное имя, которое не допускается в случае NFE, (но допускается в случае объявления функции, т.е. второго примера). Именно поэтому код назначения c=3 здесь ничего не делает.

Чтобы понять это более подробно, вы можете обновить c=3 с помощью var c=3, и в этом случае он позволит вам объявить локальную переменную именем c внутри вашего тела функции, которую вы затем можете использовать внутри функция.

b = function c(){
  console.log(c);
  var c=3;
  console.log(c);
}
b();