Почему объявления функций всегда перемещаются вверх во время оценки? - PullRequest
2 голосов
/ 07 июля 2011

На самом деле это не конкретная проблема, а то, чему я хотел бы научиться:

Насколько я понимаю, в JavaScript следующий код

if (true) {
    function greet(){ alert("Hello!"); }
} else {
    function greet(){ alert("Hi!"); }
} 
greet();

выводит Hi!, потому что код фактически оценивается примерно так:

greet = function(){ alert("Hello!"); }
greet = function(){ alert("Hi!"); }

if(true){
    // possibly a no-op assignment, such as greet = greet?
}else{
    // same as the other branch?
} 
greet();

С точки зрения языкового дизайна почему JavaScript ведет себя таким образом?

Ответы [ 3 ]

3 голосов
/ 07 июля 2011

Именованные функции создаются до запуска кода, поэтому вам не нужно помещать объявление функции перед кодом, который ее использует:

x(); // this is possible because the function already exists

function x() {}

Неважно, где находится объявление функции, даже если оно находится внутри структуры управления потоком, оно все равно создается до запуска кода. Таким образом, в вашем операторе if вообще нет исполняемого кода, даже не присваивания без операции.

Если вы хотите динамически назначать объявления функций, вы должны использовать переменную:

var greet;
if (true) {
  greet = function(){ alert("Hello!"); }
} else {
  greet = function(){ alert("Hi!"); }
} 
greet();

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

1 голос
/ 07 июля 2011

Возможно, вы нашли причуду в языке, и если вы посмотрите немного дальше, вы также найдете различные реализации.

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

А те, которые созданы или им присвоены значения по присвоению, будут иметь значения только при выполнении кода присвоения.

Итак:

// Call x
x();

// Declare x
function x(){}

работает без ошибок. Это в разговорной речи называется «подъем», то есть объявления «поднимаются» в верхней части области.

Однако, перефразируя ваш пример:

if (true) {
    function x(){
        alert('true x');
    }
} else {
    function x(){
        alert('false x');
    }
}

// In most browsers
x(); // false x

// But in Firefox
x(); // true x

Для большинства браузеров второе объявление переопределяет первое. Это связано с тем, что ECMAScript не имеет области видимости блока, только функции и глобальной области видимости.

Однако , в этом случае расширения допускаются для языка. Firefox обрабатывает вышесказанное как выражения именованных функций, поэтому показывает true x. Что еще более важно, поскольку другие браузеры обрабатывают выражения как объявления, x можно вызывать сверху блока кода, но в Firefox это невозможно, вы получите ошибку.

Суть в том, что если вы хотите условно назначить функцию для именованного параметра или переменной, сделайте это явно так:

var x;
if (true) {
    x = function (){
          alert('true x');
        };
} else {
    x = function (){
            alert('false x');
        };
}

чтобы вы получали последовательное поведение. И вы также должны помнить, что x не будет функцией до тех пор, пока после выполнения кода он не будет «поднят», потому что это не объявление.

0 голосов
/ 07 июля 2011

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

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

Теперь я могу свести ваш вопрос к следующему вопросу:

  • Почему имя функции используется в качестве имени переменной?

    A: В противном случае разработчики должны всегда назначать функции переменной (что я предпочитаю).

...