Какой синтаксис объявления функции JS является правильным в соответствии со стандартом? - PullRequest
15 голосов
/ 22 апреля 2011
  var foo = function(){ return 1; };
  if (true) {
    function foo(){ return 2; }
  }
  foo(); // 1 in Chrome // 2 in FF
  //I just want to be sure, is FF 4 not "standard" in this case?

Edit:

что если у нас есть это:

  var foo = function(){ return 1; };
  if (true) function foo(){ return 2; }      
  foo(); // is 1 standard or is 2 standard?

Ответы [ 5 ]

31 голосов
/ 22 апреля 2011

Исходный код автора не разрешен стандартом ECMAScript.(ECMAScript официальное название для спецификации языка JavaScript, по юридическим причинам.) Однако это общее расширение языка, которое, к сожалению, по-разному реализовано в разных браузерах.

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

Например, это разрешено:

  function f() {
    function g() {
      ...
    }
  }

, но это не так:

  function f() {
    {
      function g() {
        ...
      }
    }
  }

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

  function f() {
    {
      var g = function g() {
        ...
      }
    }
  }

Комитет ECMAScript рассматривает возможность выбора конкретной интерпретации для этих «операторов функций» (в отличие от определений функций).Они еще не приняли решение.Mozilla обсуждает свое предпочтительное решение здесь .

16 голосов
/ 22 апреля 2011

Код в вопросе на самом деле вообще не разрешен текущим синтаксисом ECMAScript (по состоянию на ECMAScript 5).Вы можете сделать var foo = function() {} внутри блока, но вы можете делать только function foo() {} на верхнем уровне в функциях или скриптах.

В настоящее время браузеры поддерживают код в вопросе несовместимыми способами, поскольку все они реализуют расширенияна основной язык, и они реализуют различные расширения.Полностью соответствующая реализация ECMAScript 5 фактически заканчивалась бы синтаксической ошибкой при компиляции этого сценария.

Существуют предложения добавить возможность делать подобные вещи в ECMAScript, но они еще не полностью завершены.

12 голосов
/ 22 апреля 2011

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

Причина различия состоит в том, что Chrome обрабатывает foo «объявление» как обычное объявление функции и поднимает его в началообъем.Firefox (по историческим причинам IIRC) объявляет функцию только при выполнении оператора if.

Чтобы лучше продемонстрировать разницу, вы можете попробовать запустить подобный код:

console.log(foo()); // 2 in Chrome, error in FF

var foo = function(){ return 1; };
console.log(foo()); // 1 in both Chrome and FF

if (true) {
    function foo(){ return 2; }
}
console.log(foo()); // 1 in Chrome // 2 in FF

Редактировать: Ваш второй пример точно такой же.У JavaScript нет блока, только на уровне функций и программ.«Проблема» не в том, что объявление функции находится в блоке, а в том, что это не оператор верхнего уровня.

11 голосов
/ 22 апреля 2011

Нет определенного поведения для объявления функции, не найденного на верхнем уровне программы или на верхнем уровне тела функции. Или, скорее, указанное поведение является синтаксической ошибкой, потому что грамматика JavaScript не допускает таких объявлений функций. Причина различного поведения заключается в том, что исторически браузеры были здесь по всей карте, и они остаются таковыми из-за существующих сайтов, написанных с помощью специфических для браузера путей кода, которые не позволяют никому измениться.

Строгий режим запрещает этот синтаксис , чего бы это ни стоило, и, вероятно, его определит будущая версия ECMAScript. Но пока вы не должны использовать его, потому что его поведение точно не определено спецификациями, и вы получите различное поведение в разных браузерах.

1 голос
/ 22 апреля 2011

скрипка . Это неопределенное поведение. Это беспорядок.

Как Firefox интерпретирует это, обрабатывается другими ответами

Как это интерпретирует Chrome

var foo = function() { return 1 };
if (true) {
    function foo() {
        return 2;
    }
}
console.log(foo());

В действительности function foo объявляется, а затем немедленно перезаписывается локальной переменной foo.

Это переводится на

function foo() {
    return 2;
}
var foo;
foo = function() { return 1 };
if (true) { }
console.log(foo());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...