Почему существуют два разных синтаксиса для вызова выражений анонимных функций?

Я только что прочитал статью Бена Алмана на Immediate-Invoked Function Expressions и задался вопросом об этой части, где он представляет функциональные выражения и замыкания (еще не связанные с IIFE):

// ...doesn't it stand to reason that the function expression itself can
// be invoked, just by putting () after it?

function(){ /* code goes here */ }();

// This works! Well, almost. A minor JavaScript syntax issue actually
// requires that ambiguity between function declarations and function
// expressions be eliminated, which can be done by wrapping the function
// expression in parens.

// The following pattern is used universally to create an anonymous
// closure with "privacy":

(function(){ /* code goes here */ })();

// This parens syntax is also valid (I prefer the previous version):

(function(){ /* code goes here */ }());

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

Был ли этот синтаксис сознательно введен только для вызова анонимных замыканий? Или это побочный продукт какого-то другого синтаксического свойства?

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

Может ли кто-нибудь сказать мне, что мне здесь не хватает?


person Henrik Heimbuerger    schedule 28.11.2010    source источник


Ответы (2)


Все это происходит потому, что в JavaScript есть два контекста разбора: выражение и инструкция. Запись function foo() {} на уровне оператора определяет функцию foo в этой области, тогда как function foo() {} на уровне выражения оценивает новую анонимную функцию (которая может рекурсивно вызывать себя как foo).

Итак, всякий раз, когда эта конструкция встречается, синтаксический анализатор должен определить, находится ли она на уровне выражения или оператора. По умолчанию предполагается, что он находится на уровне оператора, если не указано иное. Скобки — это синтаксический способ сказать «это выражение».

Таким образом, запись (function() {}) заставляет синтаксический анализатор рассматривать функцию как выражение. Поскольку выражения могут содержать только другие выражения (без операторов), из этого также следует, что если вы напишете (something-that-contains function(){} and-other-stuff), то функция все равно будет рассматриваться как выражение.

person Victor Nicollet    schedule 28.11.2010
comment
Отличный ответ. Как раз то, что я искал (но не мог придумать сам). :) Спасибо! - person Henrik Heimbuerger; 04.12.2010

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

person lijie    schedule 28.11.2010