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

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

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

через это:

//Bunch of code...

Ответов (19)

Решение

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

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

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

console.log(foo);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

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

Чего ждать?

Я имею в виду, если кто-то набирает иероглиф с каким-то акцентом, но мне нужны только «английские» символы AZ в моей программе? Что ж ... Испанские символы «ñ» и французские символы «é» могут быть переведены в базовые символы «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;
    }
  }
)();

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

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

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

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

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

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

Глобальная переменная имеет глобальную область видимости; он определен повсюду в вашем коде 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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Прочитал все ответы, здесь не хватает чего-то очень важного , ПОЦЕЛУЮ. Есть две основные причины, по которым мне нужны самозаполняющиеся анонимные функции, или, лучше сказать, « выражение немедленного вызова функции (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 префикса, поэтому по соглашению он не должен быть заглавным.