Какова цель самостоятельного выполнения функции в JavaScript? - PullRequest
390 голосов
/ 26 февраля 2009

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

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

за это:

//Bunch of code...

Ответы [ 16 ]

371 голосов
/ 26 февраля 2009

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

Например:

(function(){ 
    var foo = 3; 
    alert(foo); 
})(); 

alert(foo); 

Это сначала выдаст «3», а затем выдаст ошибку при следующем оповещении, потому что foo не определено.

78 голосов
/ 09 мая 2015

Simplistic. Очень нормальный вид, почти утешительный:

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

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

Подожди ... что?

Я имею в виду. Если кто-то вводит символ с каким-то акцентом (например, французский или испанский), но мне нужны только английские символы? A-Z в моей программе? Хорошо ... Испанские символы 'n ~' и французский 'e /' (я использовал два символа каждый для них, но вы, вероятно, можете сделать мысленный скачок в символ, который представляет акценты), эти символы могут быть переведены в базовые символы 'n' и 'e'.

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

Одна проблема: в нем есть функция с именем 'name', аналогичная моей функции.

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

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

Единственный способ создать область видимости кода в 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 ().

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

* +1040 * (() {}) (); * * тысяча сорок-одна

Синтаксис неловкий как грех. Тем не менее, это работает.

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

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

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

    console.log(name());

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

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

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

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

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

33 голосов
/ 19 мая 2010

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

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

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

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

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

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

19 голосов
/ 26 февраля 2009

Пространство имена. Области применения JavaScript - на уровне функций.

12 голосов
/ 13 апреля 2012

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

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

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

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

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

7 голосов
/ 27 февраля 2009

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

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

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

6 голосов
/ 26 февраля 2009

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

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

5 голосов
/ 19 ноября 2015

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

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...

4 голосов
/ 05 декабря 2017

Я прочитал все ответы, чего-то очень важного здесь не хватает , я поцелую. Есть две основные причины, по которым мне нужны самореализующиеся анонимные функции, или лучше сказать " выражение с немедленным вызовом функции (IIFE) ":

  1. Лучшее управление пространством имен (предотвращение загрязнения пространства имен -> JS Module)
  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, поэтому по соглашению его не следует использовать с заглавной буквы.

3 голосов
/ 26 февраля 2009

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

...