Замечания на странице MDN очень вводят в заблуждение. (MDN является совместно отредактированы ссылки. Это обычно отлично. Иногда он падает немного меньше этого.)
Из выше примера,
1) Является ли функция мира выражение или заявление?
2) Является ли функция c выражением или декларацией?
До ES2015 (так называемый «ES6»), они были оба неопределенного поведения потому что они были объявления функций внутри блока управления потоком. Спецификация не определяла, как их следует обрабатывать, но обработка их была «допустимым расширением» под спецификацией (blech), и некоторые из них поддерживали их. К сожалению, разные двигатели поддерживали их, делая разные вещи.
По ES2015, хотя, спецификация принимает их: Они все еще объявления функций, но как они интерпретируются изменяется в зависимости от того, ...
- ... код в строгом режиме (в котором поведение является рациональным и straightfoward),
- ... код находится в свободном режиме на браузер размещается двигатель JavaScript, который реализует опционального унаследованного поведения, описанное Annex B.3.3 и Annex B.3.4 в спецификации (путают, и есть только несколько сценариев, которые afe cross-browser),
- ... или код находится в свободном режиме в браузере без JavaScript, который в теории не должен реализовывать Приложение B (но это не останавливает их).
Поскольку в свободном режиме вы не можете быть уверены в том, будет ли двигатель JavaScript, чтобы реализовать приложение поведения B или поведение, не включенных в приложение B, единственные разумные варианты:
- Используйте строгий режим, или
- Не используйте объявления функции уровня блока.
Если вы используете строгий режим (будь то в браузере или нет), то поведение довольно проста: Декларация поднимается к верхней части своего блока и блок-Scoped (как let
и const
являются). Идентификатор, созданный объявлением, доступен для записи, и поэтому он равен , как будто декларация была преобразована в выражение функции, назначенное переменной let
в верхней части блока. Возьмем пример world
, но добавим его.
Это:
"use strict";
// ...
function example() {
if (x) {
console.log("testing:");
console.log("1:", typeof world);
function world() {}
console.log("2:", typeof world);
}
console.log("3":, typeof world);
console.log("4:", world === undefined);
}
... эффективно становится этим:
"use strict";
// ...
function example() {
if (x) {
let world = function world() {};
console.log("testing:"); // testing:
console.log("1:", typeof world); // 1: function
console.log("2:", typeof world); // 2: function
}
console.log("3:", typeof world); // 3: undefined
console.log("4:", world === undefined); // ReferenceError: `world` is not defined
}
Обратите внимание, как declaraton был поднят в верхней части блока, и блок-область видимости.
Вне строгого режима, опять же, это зависит, но, не наследие версия так же, как строгий режим но с var
вместо let
.
Итак: это:
Это:
// NOT in strict mode
function example() {
if (x) {
console.log("testing:");
console.log("1:", typeof world);
function world() {}
console.log("2:", typeof world);
}
console.log("3":, typeof world);
console.log("4:", world === undefined);
}
... эффективно становится этим:
// NOT in strict mode
function example() {
var world;
if (x) {
world = function world() {};
console.log("testing:"); // testing: (if executed)
console.log("1:", typeof world); // 1: function (if executed)
console.log("2:", typeof world); // 2: function (if executed)
}
console.log("3:", typeof world); // 3: function if `x` is truthy, undefined if `x` is falsy
console.log("4:", world === undefined); // 4: false if `x` is truthy, true if `x` is falsy
}
они оба комментарии выше них говорят, что они являются функцией выражения – DTing
@DTing Но я еще не согласен с этим. – overexchange
@overexchange Объявление функции очень легко (и часто непреднамеренно) превращается в выражение функции. Объявление функции перестает быть одним из следующих: становится частью выражения или больше не является «исходным элементом» функции или самого скрипта. «Исходный элемент» - это не-вложенный оператор в скрипте или в теле функции: – artm