Какова цель самоисполняющейся функции в javascript?

В javascript, когда вы хотите использовать это:

(function(){
    //Bunch of code...
})();

через это:

//Bunch of code...

person Ej.    schedule 26.02.2009    source источник
comment
Также посмотрите (техническую информацию) объяснение и здесь. Чтобы узнать о синтаксисе, см. почему скобки необходимы и куда они должны пойти.   -  person Bergi    schedule 17.07.2014
comment
comment
Почему перед точкой с запятой стоят две последние круглые скобки?   -  person johnny    schedule 15.12.2014
comment
@johnny - часть перед двумя последними скобками объявляет (анонимную) функцию. Эти две круглые скобки вызывают функцию.   -  person Ej.    schedule 16.12.2014
comment
Выражение немедленно вызываемой функции или IIFE - это лучшее название для это.   -  person Flimm    schedule 08.07.2015
comment
Вот полезная статья по этой теме. Благодарим Парт за его обнаружение.   -  person faintsignal    schedule 27.10.2017
comment
Похоже, что сообщество остановилось на названии Immediately Invoked Function Expression (IIFE). См. IIFE в MDN или статья в Википедии   -  person Flimm    schedule 13.10.2020
comment
Вы также можете использовать простой оператор блока { } с директивой "use strict";, а при объявлении переменных и ссылок на функции использовать ключевое слово let вместо var.   -  person caiohamamura    schedule 11.05.2021


Ответы (19)


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

Например, как упоминалось в комментарии Александра:

(function() {
  var foo = 3;
  console.log(foo);
})();

console.log(foo);

Сначала будет регистрироваться 3, а на следующем console.log будет выдана ошибка, поскольку foo не определен.

person Ken Browning    schedule 26.02.2009
comment
А также для пользы многих людей, включая целую группу инженеров Netflix: ЭТО ПРОСТО ФУНКЦИЯ. Само по себе это не означает закрытие. Иногда автоматические вызовы используются в сочетании со сценариями, относящимися к закрытию, чтобы делать аккуратные вещи, но если вы не видите, что что-то держится за ссылку, которая была бы собрана мусором и ушла на языке, не являющемся закрытием, ей нечего делать. черт возьми с ЗАКРЫТИЯМИ. - person Erik Reppen; 18.08.2012
comment
Значит, это в основном используется с закрытием? - person Pir Abdul; 13.02.2013
comment
@AlexanderBird, не совсем верно ... если обойтись без var, вот так: ...function(){ foo=3;}? Он бы установил глобальную переменную, не так ли? - person T.Todua; 25.11.2016
comment
@AlexanderBird, но это уже происходит в локальных переменных внутри функций: function(){ var foo = 3; alert(foo); }; alert(foo); Так что я до сих пор не понимаю - person João Pimentel Ferreira; 03.12.2017
comment
Ах, я понял, вы достигаете всех этих трех функций одновременно: 1) вы выполняете функцию, только объявляя ее; 2) Как и любая функция, область видимости переменных является только локальной; и 3) функция может быть анонимной, не загрязняя основную область видимости. - person João Pimentel Ferreira; 03.12.2017
comment
@ T.Todua: Вы правы, что var не нужен (и последствия). Однако суть этого ответа в том, что из-за самоисполняющихся функций теперь возможно вообще иметь частную область видимости (с помощью var) - person Alexander Bird; 04.12.2017
comment
Если это только для обзора, почему бы просто не использовать { let foo = 3 }? - person Giulio; 20.08.2020
comment
@Giulio Это ответ от 2009 года. Блочная область видимости была введена позже. - person yunzen; 01.03.2021

Упрощенно. Так нормально выглядит, это почти утешает:

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

Однако что, если я добавлю на свою страницу действительно удобную библиотеку javascript, которая переводит продвинутые символы в их представления базового уровня?

Чего ждать?

Я имею в виду, если кто-то набирает иероглиф с каким-то акцентом, но мне нужны только «английские» символы A-Z в моей программе? Что ж ... Испанские символы «ñ» и французские символы «é» могут быть переведены в базовые символы «n» и «e».

Итак, кто-то хороший человек написал всеобъемлющий конвертер символов, который я могу включить на свой сайт ... Я включаю его.

Одна проблема: в нем есть функция, называемая «имя», как и моя функция.

Это то, что называется столкновением. У нас есть две функции, объявленные в одной области действия с одинаковым именем. Мы хотим этого избежать.

Итак, нам нужно как-то расширить наш код.

Единственный способ ограничить код в javascript - обернуть его функцией:

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

Это могло бы решить нашу проблему. Теперь все заключено и доступно только через открывающую и закрывающую фигурные скобки.

У нас есть функция в функции ... что странно на вид, но полностью законно.

Только одна проблема. Наш код не работает. Наша переменная userName никогда не отображается в консоли!

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

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

main();

Или раньше!

main();

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

Второстепенная проблема: каковы шансы, что имя «основной» еще не использовалось? ... такой очень, очень тонкий.

Нам нужно БОЛЬШЕ масштабирования. И какой-то способ автоматически выполнить нашу функцию main ().

Теперь мы переходим к функциям автоматического выполнения (или самовыполняющимся, самовыполняющимся и т. Д.).

((){})();

Синтаксис грубоват как грех. Однако это работает.

Когда вы заключаете определение функции в круглые скобки и включаете список параметров (другой набор или круглые скобки!), Оно действует как вызов функции.

Итак, давайте снова посмотрим на наш код с некоторым самоисполняющимся синтаксисом:

(function main() {
  var userName = "Sean";

    console.log(name());

    function name() {
      return userName;
    }
  }
)();

Итак, в большинстве учебных пособий, которые вы читаете, вас будут засыпать термином «анонимное самовыполнение» или чем-то подобным.

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

Когда что-то пойдет не так (а это произойдет), вы будете проверять обратную трассировку в своем браузере. Когда записи в трассировке стека имеют имена, всегда легче сузить круг проблем с кодом!

Очень многословный, и я надеюсь, что это поможет!

person Sean Holden    schedule 09.05.2015
comment
Спасибо :) Я искал в Интернете все время, пытаясь понять преимущества IIFE по сравнению с обычными функциями с точки зрения переменной конфиденциальности, и ваш ответ просто лучший. Все говорят, что одним из лучших преимуществ является то, что переменные и функции внутри IIFE «наконец» закрыты, когда обычная функция дает вам то же самое. Наконец, я думаю, что понял это благодаря вашему процессу объяснения. В конце концов, IIFE - это всего лишь функция, но теперь я понимаю, зачем ее использовать. Еще раз спасибо! - person viery365; 20.09.2016
comment
Спасибо, что нашли время так хорошо это объяснить. - person MSC; 30.09.2016
comment
Хороший ответ. Однако у меня есть вопрос по вашему последнему пункту - когда вы рекомендуете называть все функции, вы говорите, что есть способ сделать это с помощью самовыполняющихся функций, или предлагаете всем дать имя функции, а затем вызвать ее? ИЗМЕНИТЬ О, понятно. Этот уже назван. Ага. Вы можете указать, что оправдываете использование именованной самоисполняющейся функции. - person FireSBurnsmuP; 06.04.2017
comment
Что ж, друг мой, это тот ответ, который я искал :) - person João Pimentel Ferreira; 03.12.2017
comment
Я всегда люблю 2 типа ответов; (1.) коротко, четко и по делу. (2.) Рассказ, подобный объяснению, который навсегда останется в вашем мозгу. Ваши подпадают под (2.) - person Vibhor Dube; 18.06.2020

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

Я большой поклонник этого :) потому что:

  • Он сводит код к минимуму
  • Он обеспечивает отделение поведения от представления
  • Он обеспечивает закрытие, предотвращающее конфликты имен.

Чрезвычайно - (Почему ты должен говорить, что это хорошо?)

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

Подробнее см. здесь.

person M A Hossain Tonu    schedule 19.05.2010
comment
Пункт 1. Как? Пункт 2. Это совершенно другая передовая практика. Пункт 3. Какая функция не работает? 4,5,6,7. Актуальность? 8. Думаю, 1/8 неплохо. - person Erik Reppen; 18.08.2012
comment
С опозданием на семь лет, но для пункта 1. он вообще не сокращает код, фактически он добавляет минимум две строки кода при создании функции. - person ICW; 03.03.2017
comment
Единственная точка здесь заключается в том, что он обеспечивает закрытие, которое предотвращает конфликты именования, все остальные точки являются переформулировкой этого или ложными. может ты можешь упростить свой ответ? - person pcarvalho; 18.12.2018

Пространство имен. Области видимости JavaScript являются функциональными.

person Christoph    schedule 26.02.2009
comment
все еще поступают отрицательные голоса, потому что я использовал namespacing вместо scoping; это вопрос определения - см., например, Википедия: Пространство имен в информатике ( иногда также называется областью имен), представляет собой абстрактный контейнер или среду, созданную для хранения логической группы уникальных идентификаторов или символов (т. е. имен). и Идентификатор пространства имен может обеспечивать контекст (Область применения в информатике ) к имени, и эти термины иногда используются как синонимы. - person Christoph; 01.10.2014
comment
Области функционального уровня Javascript предоставляют пространство, в котором находятся имена переменных, пространство имен; что это анонимный, не связанный с идентификатором пространства имен, не имеет значения ... - person Christoph; 01.10.2014

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

Конструкция (function(){})() не защищает от подразумеваемых глобальных переменных, что для меня является большей проблемой, см. http://yuiblog.com/blog/2006/06/01/global-domination/

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

Более лаконичный синтаксис var App = {} обеспечивает аналогичный уровень защиты и может быть заключен в функциональный блок на «общедоступных» страницах. (см. Ember.js или SproutCore для реальных примеров библиотек, использующих эту конструкцию)

Что касается свойств private, они отчасти переоценены, если вы не создаете общедоступную структуру или библиотеку, но если вам нужно их реализовать, У Дугласа Крокфорда есть несколько хороших идей.

person David W. Keith    schedule 13.04.2012
comment
Строгий режим защищает от подразумеваемых глобальных переменных. Это в сочетании с автозапуском поможет вам. Я никогда не понимал шумихи из-за частной собственности. Объявите переменные внутри конструктора функций. Выполнено. Если мысль о том, что вы забыли использовать ключевое слово new, не дает вам уснуть по ночам, напишите фабричную функцию. Сделано снова. - person Erik Reppen; 18.08.2012

Я прочитал все ответы, здесь не хватает чего-то очень важного, ПОЦЕЛУЮ. Есть две основные причины, по которым мне нужны самозаполняющиеся анонимные функции, или, лучше сказать, «Выражение немедленного вызова функции (IIFE)»:

  1. Лучшее управление пространством имен (Избегание загрязнения пространства имен -> Модуль JS)
  2. Замыкания (имитация членов частного класса, как известно из ООП)

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

var MyClosureObject = (function (){
  var MyName = 'Michael Jackson RIP';
  return {
    getMyName: function () { return MyName;},
    setMyName: function (name) { MyName = name}
  }
}());

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

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

Попробуем поэкспериментировать:

Я могу получить MyName, используя getMyName, и он работает:

 console.log(MyClosureObject.getMyName()); 
 // Michael Jackson RIP

Следующий простодушный подход не сработает:

console.log(MyClosureObject.MyName); 
// undefined

Но я могу задать другое имя и получить ожидаемый результат:

MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName()); 
// George Michael RIP

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

person Lonely    schedule 05.12.2017

Возможно, изоляция области действия. Чтобы переменные внутри объявления функции не загрязняли внешнее пространство имен.

Конечно, в половине реализаций JS они все равно будут.

person chaos    schedule 26.02.2009
comment
Какие бы это были реализации? - person Matthew Crumley; 27.02.2009
comment
Любая реализация, написанная не в строгом режиме и содержащая и неявное объявление var, которое делает ее глобальной. - person Erik Reppen; 18.08.2012

Есть ли параметр, а «Связка кода» возвращает функцию?

var a = function(x) { return function() { document.write(x); } }(something);

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

person stesch    schedule 26.02.2009
comment
+1; Я предпочитаю явное var x = something; во внешней функции, а не x в качестве параметра, хотя: я думаю, это более читабельно ... - person Christoph; 27.02.2009
comment
@Christoph: Если значение чего-то изменится после создания функции, то оно будет использовать новое значение, а не то, что было во время создания. - person stesch; 27.02.2009
comment
@stesch: откуда ты это взял? Насколько я знаю, это не так; единственный способ получить настоящие ссылки в JS - использовать объект arguments, но даже это работает не во всех браузерах - person Christoph; 27.02.2009
comment
@Christoph: JavaScript: The Good Parts, Дуглас Крокфорд (О'Рейли) - person stesch; 27.02.2009
comment
@stesch: это не работает так, как вы это описываете: новое значение будет использовано, если вы отбросите переменную x и напрямую зависит от лексической области, т.е. _2 _... - person Christoph; 27.02.2009
comment
..._ 1_ необходимо (либо как параметр, либо как локальная переменная), если вы хотите сохранить значение при создании, даже если оно изменяется во внешней области - person Christoph; 27.02.2009

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

for( var i = 0; i < 10; i++ ) {
  setTimeout(function(){
    console.log(i)
  })
}

Выход: 10, 10, 10, 10, 10...

for( var i = 0; i < 10; i++ ) {
  (function(num){
    setTimeout(function(){
      console.log(num)
    })
  })(i)
}

Выход: 0, 1, 2, 3, 4...

person sg.cc    schedule 19.11.2015
comment
не могли бы вы подробнее рассказать о том, что происходит с первым набором кода - person radio_head; 30.11.2017
comment
С let вместо var в первом случае все будет в порядке. - person Vitaly Zdanevich; 21.09.2018

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

person Guffa    schedule 26.02.2009

Сначала вы должны посетить MDN IIFE. Теперь кое-что об этом

  • это выражение немедленно вызываемой функции. Поэтому, когда ваш файл javascript вызывается из HTML, эта функция вызывается немедленно.
  • Это предотвращает доступ к переменным в рамках идиомы IIFE, а также загрязняет глобальную область видимости.
person JustIn    schedule 11.03.2020

Самостоятельно выполняющиеся функции используются для управления областью переменной.

Область видимости переменной - это область вашей программы, в которой она определена.

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

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

var globalvar = "globalvar"; // this var can be accessed anywhere within the script

function scope() {
    alert(globalvar);
    var localvar = "localvar"; //can only be accessed within the function scope
}

scope(); 

Таким образом, в основном самоисполняющаяся функция позволяет писать код, не заботясь о том, как именуются переменные в других блоках кода javascript.

person Adeojo Emmanuel IMM    schedule 24.04.2018

Поскольку функции в Javascript являются объектами первого класса, определяя его таким образом, он фактически определяет «класс» во многом так же, как C ++ или C #.

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

person James Curran    schedule 26.02.2009

Самостоятельно запускаемая функция в javascript:

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

person Kishor Vitekar    schedule 20.10.2015

(function(){
    var foo = {
        name: 'bob'
    };
    console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error

Фактически, указанная выше функция будет рассматриваться как выражение функции без имени.

Основная цель заключения функции закрывающими и открытыми круглыми скобками - избежать загрязнения глобального пространства.

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

person Madhankumar    schedule 31.03.2017

Краткий ответ: для предотвращения загрязнения Глобального (или более высокого) масштаба.

IIFE (Immediately Invoked Function Expressions) - лучший метод для написания скриптов в виде надстроек, надстроек, пользовательских скриптов или любых других скриптов, которые, как ожидается, будут работать со скриптами других людей. Это гарантирует, что любая определяемая вами переменная не окажет нежелательного воздействия на другие скрипты.

Это другой способ написать выражение IIFE. Лично я предпочитаю следующий метод:

void function() {
  console.log('boo!');
  // expected output: "boo!"
}();

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void

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

person Donovan P    schedule 20.12.2019
comment
Хорошо, я раньше не видел такого использования void. Мне это нравится. - person Ej.; 20.12.2019

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

Я знаю, когда мне нравится использовать самоисполняющиеся функции.

var myObject = {
    childObject: new function(){
        // bunch of code
    },
    objVar1: <value>,
    objVar2: <value>
}

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

object: {
    childObject: {
        childObject: {<value>, <value>, <value>}
    }, 
    objVar1: <value>,
    objVar2: <value>
}

В кодировании вообще есть много неясных способов делать много одних и тех же вещей, что заставляет задуматься: «Зачем беспокоиться?» Но продолжают появляться новые ситуации, когда вы больше не можете полагаться только на базовые / основные принципы.

person Garrett    schedule 18.12.2016

Учитывая ваш простой вопрос: «В javascript, когда вы хотите использовать это: ...»

Мне нравятся ответы @ken_browning и @ sean_holding, но вот еще один вариант использования, о котором я не упоминал:

let red_tree = new Node(10);

(async function () {
    for (let i = 0; i < 1000; i++) {
        await red_tree.insert(i);
    }
})();

console.log('----->red_tree.printInOrder():', red_tree.printInOrder());

где Node.insert - какое-то асинхронное действие.

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

person zentechinc    schedule 06.04.2020

IIRC позволяет создавать частные свойства и методы.

person Ólafur Waage    schedule 26.02.2009