2015-08-10 3 views
3

Я читаю на JavaScript IIFE и до сих пор понимает концепцию, но мне интересно, что такое внешняя скобка. В частности, зачем они нужны? Например,Зачем нужны скобки вокруг JavaScript IIFE?

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

отлично работает, но

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

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

+4

Одним словом: двусмысленность. Я не помню точные термины, но 'function() {...}' является объявлением, а '(function() {...})' является выражением, выражение, вызываемое значением '()' работает. –

+2

FYI, это также работает ~ '+ function() {...}()' as does!! Function() {...}() ' – Phil

+0

Один из функций, которые интерпретатор оценивает. Другое - это определение функции, которое интерпретатор просто добавляет определение функции в текущую область. Параны превращают его в выражение функции, которое вы хотите. Почему он работает таким образом из-за деталей языковой грамматики. – jfriend00

ответ

3

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

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

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

Advanced JavaScript: Why is this function wrapped in parentheses?

ПОДСКАЗКА:

Оператор вызова (()) работает только с выражениями, а не деклараций.

+1

* «Приходится» * является немного сильным термином. Есть и другие способы разграничения выражения – Phil

+0

@Phil, спасибо за коррекцию bro :) –

+0

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

5

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

Объявление функции само по себе является оператором, а сами утверждения не возвращают значения (давайте также проигнорируем, как отладочная консоль или Node.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(){})() 

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

+0

, это очень хороший ответ! –

2

Это будет длинный ответ, но даст вам необходимый фон. В 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 - сборщик мусора. В вашем примере оператор группировки () принуждает его содержимое к выражению, поэтому функция является выражением и может быть вызвана немедленно как таковая.

Важно отметить, что разница между моим первым примером 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" 
Смежные вопросы