Почему скобки необходимы вокруг JavaScript IIFE? [дубликат]

этот вопрос уже есть ответ здесь:

Я читаю на JavaScript IIFE и до сих пор понимаю концепцию, но мне интересно о внешней скобке. В частности, почему они необходимы? Для пример,

(function() {var msg='I love JavaScript'; console.log(msg);}());

работает, а

function() {var msg='I love JavaScript'; console.log(msg);}();

генерирует синтаксическую ошибку. Почему? Есть много дискуссий по IIFE, но я не вижу четкого объяснения того, почему требуются круглые скобки.

3 ответов


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

http://benalman.com/news/2010/11/immediately-invoked-function-expression/

для более подробного объяснения см.:

расширенный JavaScript: почему эта функция заключена в круглые скобки?

подсказка:

ссылка оператор (()) работает только с выражениями, а не с объявлениями.


существует два способа создания функций в JavaScript (ну, 3, но давайте проигнорируем new Function()). Вы можете либо написать объявление функции, либо написать выражение функции.

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

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

var x = function () {};

может возникнуть соблазн заключить, что синтаксис:

function () {};

это то, что делает это выражение. Но это неправильно. Синтаксис выше-это то, что делает его анонимной функцией. Анонимные функции могут быть объявлением или выражением. Что делает это выражение это синтаксис:

var x = ...

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

некоторые из форм выражений в JavaScript включают:

  • Все права = оператор
  • вещи в скобки () это не вызов функции брекеты
  • все справа от математического оператора (+,-,*,/)
  • все аргументы троичного оператора .. ? .. : ..

когда вы пишете:

function () {}

это объявление и не возвращает значение (заявленные функции). Поэтому попытка вызвать не-результат является ошибкой.

но когда вы пишете:

(function () {})

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

обратите внимание на правила для того, что считается выше выражений. Из этого следует, что скобки-это не единственные вещи, которые вы можете использовать для создания IIFE. Ниже приведены допустимые способы построения IIFEs (поскольку мы пишем выражения функций):

tmp=function(){}()

+function(){}()

-function(){}()

0/function(){}()

0*function(){}()

0?0:function(){}()

(function(){}())

(function(){})()

вы можете увидеть один из вышеперечисленных нестандартных форм (в частности,+ версия) в третьей стороне библиотеки, потому что они хотят сохранить один байт. Но я настоятельно рекомендую вам использовать только формы скобок (либо хорошо), потому что они широко признаны другими программистами как IIFEs.


это будет многословный ответ, но даст вам необходимый фон. В JavaScript есть два способа определения функций: Определение функции (классический вид)

function foo() {
  //why do we always use
}

и затем более неясный тип, выражение функции

var bar = function() {
  //foo and bar
};

в сущности, то же самое происходит и при исполнении. Создается объект функции, выделяется память и к функции привязывается идентификатор. Разница в синтаксисе. Бывший само по себе утверждение, которое объявляет новую функцию, последняя является выражением.

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

setTimeout(500, function() {
  //for examples
});

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

var fourteen = function sumOfSquares() {
  var value = 0;
  for (var i = 0; i < 4; i++)
    value += i * i;
  return value;
}();

здесь sumOfSquares немедленно вызывается, потому что он может быть признан выражением. fourteen становится 14 и sumOfSquares будет собран "мусор". в вашем примере оператор группировки () coerces свое содержание в выражение, поэтому функция выражение и может быть вызвана немедленно как такие.

одна важная вещь, чтобы отметить разницу между моим первым примером foo и bar, хотя это подъем. Если вы не знаете, что это такое, быстрый поиск Google или два должны сказать вам, но быстрое и грязное определение заключается в том, что подъем-это поведение JavaScript, чтобы принести объявления (переменные и функции) в верхнюю часть области. Эти объявления обычно поднимают только идентификатор, но не его инициализированное значение, поэтому вся область сможет увидеть переменная / функция, прежде чем ей будет присвоено значение.

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

console.log("lose your " + function() {
  fiz(); //will execute fiz
  buzz(); //throws TypeError
  function fiz() {
    console.log("lose your scoping,");
  }
  var buzz = function() {
    console.log("and win forever");
  };
  return "sanity";
}()); //prints "lose your scoping, lose your sanity"