Почему эта функция заключена в круглые скобки, а затем скобки?

Я вижу это все время в javascript-источниках, но я никогда не обнаружил реальной причины, по которой эта конструкция используется. Почему это необходимо?

(function() {

    //stuff

})();

Почему это написано так? Почему бы просто не использовать stuff самостоятельно, а не в функции?

EDIT: я знаю, что это определение анонимной функции, а затем ее вызов, но почему?

Ответ 1

Это определяет замыкание функции

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

Рассмотрим следующий код:

(function(){
    var test = true;
})();

variable test не видна нигде, кроме встроенного закрытия функции, где она определена.

Что такое закрытие?

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

Проверьте этот код и прочитайте комментарии вместе с ним:

// public part
var publicVar = 111;
var publicFunc = function(value) { alert(value); };
var publicObject = {
    // no functions whatsoever
};

    // closure part
    (function(pubObj){
        // private variables and functions
        var closureVar = 222;
        var closureFunc = function(value){
            // call public func
            publicFunc(value);
            // alert private variable
            alert(closureVar);
        };

        // add function to public object that accesses private functionality
        pubObj.alertValues = closureFunc;

        // mind the missing "var" which makes it a public variable
        anotherPublic = 333;

    })(publicObject);

// alert 111 & alert 222
publicObject.alertValues(publicVar);

// try to access varaibles
alert(publicVar); // alert 111
alert(anotherPublic); // alert 333
alert(typeof(closureVar)); // alert "undefined"

Здесь JSFiddle running code, который отображает данные, как указано комментариями в верхнем коде.

Что он на самом деле делает?

Как вы уже знаете это

  • создает функцию:

    function() { ... }
    
  • и сразу же выполняет его:

    (func)();
    
  • эта функция может принимать или не принимать дополнительные параметры.

Плагины jQuery обычно определяются таким образом, определяя функцию с одним параметром, который плагин манипулирует внутри:

(function(paramName){ ... })(jQuery);

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

Ответ 2

Эта конструкция известна как самоисполняющаяся анонимная функция, которая на самом деле не очень хорошее имя для нее, вот что происходит (и почему имя не является хорошим). Это:

function abc() {
    //stuff
}

Определяет функцию, называемую abc, если мы хотим анонимную функцию (которая является очень распространенным шаблоном в javascript), это будет нечто вроде следующих:

function() {
    //stuff
}

Но, если у вас есть это, вам нужно либо связать его с переменной, чтобы вы могли ее вызвать (что сделало бы ее не-анонимным), или вам нужно немедленно ее выполнить. Мы можем попытаться выполнить его сразу, сделав это:

function() {
    //stuff
}();

Но это не сработает, так как это даст вам синтаксическую ошибку. Причина, по которой вы получаете синтаксическую ошибку, выглядит следующим образом. Когда вы создаете функцию с именем (например, abc выше), это имя становится ссылкой на функцию выражение, вы можете затем выполнить выражение, поставив() после имя, например: abc(). Акт объявления функции не создает выражение, объявление функции представляет собой инструкцию, а не выражение. По сути, выражение является исполняемым, а утверждения не являются (как вы могли догадаться). Поэтому, чтобы выполнить анонимную функцию, вам нужно сказать парсеру, что это выражение, а не оператор. Один способ сделать это (не единственный способ, но стал конвенцией), состоит в том, чтобы обернуть вашу анонимную функцию в набор (), и вы получите свою конструкцию:

(function() {
    //stuff
})();

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

Итак, почему все это полезно, одна причина заключается в том, что он позволяет вам остановить ваш код от загрязнения глобального пространства имен. Поскольку функции в javascript имеют свою собственную область видимости, любая переменная внутри функции не видна глобально, поэтому, если бы мы могли как-то написать весь наш код внутри функции, глобальная область была бы безопасной, то наша самоисполняющаяся анонимная функция позволяет нам делать именно это, Позвольте мне взять пример из старой книги Джона Ресига:

// Create a new anonymous function, to use as a wrapper
(function(){
  // The variable that would, normally, be global
  var msg = "Thanks for visiting!";
  // Binding a new function to a global object
  window.onunload = function(){
    // Which uses the 'hidden' variable
    alert( msg );
  };
  // Close off the anonymous function and execute it
})();

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

Но подождите еще больше:). Эта конструкция позволяет решить проблему, которая иногда возникает при использовании закрытий в javascript. Я еще раз позволю Джону Ресигу объяснить, я цитирую:

Помните, что закрытие позволяет вам ссылаться на переменные, которые существуют внутри родительской функции. Однако он не дает значения переменная в момент ее создания; он дает последнее значение переменная в родительской функции. Наиболее распространенная проблема, которые вы увидите, это происходит во время цикла for. Есть один переменную, используемую в качестве итератора (например, i). Внутри цикла for, создаются новые функции, которые используют замыкание для ссылки итератор снова. Проблема в том, что к тому времени, когда новые закрытые вызываются функции, они будут ссылаться на последнее значение итератор (т.е. последняя позиция в массиве), а не значение, которое вы ожидал бы. В листинге 2-16 показан пример использования анонимного функции, чтобы вызвать область действия, создать экземпляр, в котором ожидается возможно закрытие.

// An element with an ID of main
var obj = document.getElementById("main");

// An array of items to bind to
var items = [ "click", "keypress" ];

// Iterate through each of the items
for ( var i = 0; i < items.length; i++ ) {
  // Use a self-executed anonymous function to induce scope
  (function(){
    // Remember the value within this scope
    var item = items[i];
    // Bind a function to the element
    obj[ "on" + item ] = function() {
      // item refers to a parent variable that has been successfully
      // scoped within the context of this for loop
      alert( "Thanks for your " + item );
    };
  })();
}

По сути, все это означает, что люди часто пишут наивный код javascript, подобный этому (это наивная версия цикла сверху):

for ( var i = 0; i < items.length; i++ ) {
    var item = items[i];
    // Bind a function to the elment
    obj[ "on" + item ] = function() {
      alert( "Thanks for your " + items[i] );
    };
}

Функции, которые мы создаем в цикле, являются закрытиями, но, к сожалению, они блокируют значение last i из охватывающей области (в этом случае это, вероятно, будет 2, что вызовет беда). Скорее всего, мы хотим, чтобы каждая функция, которую мы создавали в цикле, блокировала значение я в момент его создания. Именно здесь приходит наша самопроизводящая анонимная функция, вот аналогичный, но, возможно, более простой способ переписать этот цикл:

for ( var i = 0; i < items.length; i++ ) {
  (function(index){
    obj[ "on" + item ] = function() {
      alert( "Thanks for your " + items[index] );
    };
  })(i);
}

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

Вот вы, две хорошие причины, чтобы использовать самопроизвольную анонимную конструкцию функции и почему она на самом деле работает в первую очередь.

Ответ 3

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

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

Ответ 4

Это "анонимная функция самоисполнения" или "непосредственное выражение-функция-выражение". Хорошее объяснение от Бен Альмана здесь.

Я использую шаблон при создании пространств имен

var APP = {};

(function(context){



})(APP);

Ответ 5

Такая конструкция полезна, когда вы хотите сделать закрытие. Конструкция помогает создать частную "комнату" для недоступных извне переменных. Подробнее в этой главе книги "JavaScript: хорошие части": http://books.google.com/books?id=PXa2bby0oQ0C&pg=PA37&lpg=PA37&dq=crockford+closure+called+immediately&source=bl&ots=HIlku8x4jL&sig=-T-T0jTmf7_p_6twzaCq5_5aj3A&hl=lv&ei=lSa5TaXeDMyRswa874nrAw&sa=X&oi=book_result&ct=result&resnum=1&ved=0CBUQ6AEwAA#v=onepage&q&f=false

В примере, показанном вверху на стр. 38, вы видите, что переменная "статус" скрыта в закрытии и не может быть доступна в любом случае, кроме вызова метода get_status().

Ответ 6

Я не уверен, что на этот вопрос уже дан ответ, поэтому извиняюсь, если я просто повторяю материал.

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

Итак, это хороший способ не загрязнять глобальную область.

Должно быть только несколько глобальных переменных. Помните, что каждый глобальный объект является свойством объекта window, который по умолчанию имеет много свойств. Внедрение новой области также позволяет избежать столкновений со свойствами по умолчанию объекта window.