Неоднозначное объявление функции в Javascript - PullRequest
11 голосов
/ 15 января 2010

Я новичок в Javascript и был озадачен тем, как работает объявление функции. Я провёл тест и получил интересные результаты:

say();

function say()
{
    alert("say");
}

Форвард-декларация сработала и всплывающее окно "сказать"

На противоположном

say();

say = function()
{
    alert("say");
}

не работал, хотя он также объявил объект функции

Если мы объявим функцию и объявим ее потом:

function say()
{
    alert("speak");
}

say();

function say()
{
    alert("say");
}

Я получил «сказать» вместо «говорить». Это сюрприз!

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

say = function()
{
    alert("speak");
}

say();

function say()
{
    alert("say");
}

say();

Еще один сюрприз, это было «говорить», а затем «говорить». «Обычное» объявление функции вообще не работает!

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

Другой вопрос: только с форматом объекта функции становится ли это предварительное объявление невозможным? Есть ли способ «смоделировать» это в Javascript?

Ответы [ 4 ]

3 голосов
/ 15 января 2010

Javascript работает так:

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

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

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

Эти функции являются членами объекта window, они фактически объявлены глобально. Если вы присвоите локальную переменную значению функции, то эта локальная переменная будет иметь приоритет над членами в объекте window. Если javascript не может найти локальную переменную, он ищет ее в области видимости, объект window является последним средством. Вот что произошло в вашем последнем примере: у него есть переменная say, которая находится в более конкретной области видимости, чем глобальная функция say.

Если вы переопределите say во время выполнения, то есть поменяйте местами порядок объявлений в вашем последнем примере, тогда вы увидите два разных предупреждения, которые вы ожидаете:

say(); //speak, the global function

function say() {
  alert('speak');
}

var say = function() {
  alert('say');
}

say(); //say, the declared local variable
1 голос
/ 15 января 2010
say();

function say()
{
    alert("say");
}

Здесь интерпретатор выбирает определение say() при его вызове и выполняет его.

say();

say = function()
{
    alert("say");
}

Здесь нет определения say() для извлечения - вместо этого вы назначаете анонимную функцию переменной. Интерпретатор не может «найти» это так, как он может найти предварительные объявления.

function say()
{
    alert("speak");
}

say();

function say()
{
    alert("say");
}

Здесь say определяется, а затем переопределяется - последнее определение выигрывает.

say = function()
{
    alert("speak");
}

say();

function say()
{
    alert("say");
}

say();

Здесь say - это переменная, указывающая на анонимную функцию (после интерпретации первого оператора). Это имеет приоритет над любым определением функции, так же, как если бы вы поместили определение функции перед присваиванием.

Но если бы у вас было

say();

say = function()
{
    alert("speak");
}

say();

function say()
{
    alert("say");
}

Тогда вы получите «сказать», а затем «говорить».

0 голосов
/ 15 января 2010

Всегда хорошая идея вызывать функцию позже, хотя javascript работает так.

Большинство языков не будут работать таким образом, вместо этого сделайте это.

function say(){
    alert("say");
}

say();

или

say = function(){
    alert("say");
}

say();

или

(function(){
    alert("say");
})();
0 голосов
/ 15 января 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...