Яка мета самовиконання функції у javascript?


427

У JavaScript, коли ви хочете використовувати це:

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

над цим:

//Bunch of code...

3
Подивіться також на ( технічне ) пояснення і тут . Для синтаксису подивіться, чому потрібні дужки та куди вони повинні йти .
Бергі


Чому він має дві останні дужки, безпосередньо перед крапкою з комою?
Johnny

3
@johnny частина перед цими двома останніми дужками оголошує (анонімну) функцію. Ці дві дужки викликають функцію.
Ей.

7
"Негайно викликана функція вираження" або IIFE - краща назва цього.
Flimm

Відповіді:


404

Вся справа в змінному масштабі. Змінні, оголошені у функції самовиконання, за замовчуванням доступні лише для кодування в межах функції самовиконання. Це дозволяє писати код без побоювання того, як названі змінні в інших блоках коду JavaScript.

Наприклад, як згадується в коментарі Олександра :

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

console.log(foo);

Це спочатку увійде в журнал, 3а потім видасть помилку на наступному, console.logоскільки fooне визначено.


7
А також на користь багатьох людей, у тому числі цілу купу інженерів Netflix: ОСТОРОЖНО ФУНКЦІЯ. Він сам по собі не є представником закриття. Іноді автовикликачі використовуються разом із відповідними сценаріями закриття, щоб робити акуратні речі, але якщо ви не бачите, що щось посилається на посилання, яке було б зібране сміттям і не перебуває на мові, що не закривається, це не має нічого freaking зробити з ЗАКРИТИМИ.
Ерік Реппен

2
Так це означає, що його в основному використовують із закриттям?
Пір Абдул

@AlexanderBird, не зовсім правильно ... якщо ви не var, як це: ...function(){ foo=3;}? Це встановило б глобальну змінну, правда?
Т.Тодуа

2
@AlexanderBird, але це вже трапляється в локальних змінних всередині функцій: function(){ var foo = 3; alert(foo); }; alert(foo);Тому я все одно не отримую цього
Жоао Піментел Феррейра

Ах, я розумію, ви отримуєте всі ці 3 функції одразу: 1) Ви виконуєте функцію, лише оголошуючи її; 2) Як і будь-яка функція, область змінних є лише локальною; та 3) Ця функція може бути анонімною, не забруднюючи основну сферу застосування
Жоао Піментел Феррейра

94

Спрощений. Це дуже нормальний вигляд, його майже втішне:

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;
  }
}

Побічна проблема: Які шанси, що назва "головний" ще не використовується? ... так дуже, дуже струнка.

Нам потрібно БІЛЬШЕ масштабування. І якийсь спосіб автоматично виконати нашу основну () функцію.

Тепер ми переходимо до функцій автоматичного виконання (або самовиконання, самостійного запуску, будь-чого).

((){})();

Синтаксис незручний як гріх. Однак це працює.

Коли ви загортаєте визначення функції в дужки та включаєте список параметрів (інший набір чи круглі дужки!), Він виконує функцію виклику функції .

Тож давайте переглянемо наш код ще раз із деяким синтаксисом, що виконує себе:

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

    console.log(name());

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

Отже, у більшості прочитаних вами навчальних посібників ви зараз будете бомбардувати терміном "анонімне самовиконання" чи чимось подібним.

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

Коли щось піде не так (і це станеться), ви будете перевіряти відстань у своєму браузері. Це завжди легше скоротити ваші питання коду під час запису в трасуванні стека мають імена!

Величезна довговільна і сподіваюся, що це допоможе!


2
Дякую :) Я шукав в Інтернеті увесь шлях, намагаючись зрозуміти переваги IIFE щодо нормальних функцій з точки зору змінної конфіденційності, і ваша відповідь просто найкраща. Всі кажуть, що однією з найкращих переваг є те, що змінні та функції всередині IIFE є "нарешті" приватними, коли нормальна функція дає вам точно те саме. Нарешті, я думаю, я отримав це через ваш процес пояснення. IIFE - це лише функція, але тепер я розумію, для чого її використовувати. Дякую ще раз!
viery365

Дякуємо, що знайшли час, щоб так добре пояснити це.
MSC

Гарна відповідь. Однак у мене є питання щодо останнього пункту - Коли ви рекомендуєте називати всі функції, чи говорите ви, що існує спосіб зробити це за допомогою функцій самовиконання, або ви пропонуєте, щоб усі назвали цю функцію, а потім викликати її? РЕДАКЦІЯ О, бачу. Цей уже названий. Дух. Можливо, ви хочете зазначити, що ви виправдовуєте використання іменованої функції самовиконання.
FireSBurnsmuP

Ну мій друг, це відповідь, яку я шукав:)
Жоао Піментел Феррейра

Це відповідь, яку я шукав, а не той, який позначений як прийнятий. Чи правильно я кажу, що йдеться не про зіткнення імені змінної , а про зіткнення імені функції ? Змінні навіть у звичайних функціях, які не є iife, локально оцінюються і не стикаються з глобальними змінними, чи не так?
Кумар Маніш

32

Самовикликання (також відоме як автоматичне виклик) - це коли функція виконується негайно після її визначення. Це основний зразок і служить основою для багатьох інших моделей розвитку JavaScript.

Я великий шанувальник :), тому що:

  • Він зводить код до мінімуму
  • Це примушує відокремлювати поведінку від уявлення
  • Він забезпечує закриття, яке запобігає називанню конфліктів

Приємно - (Чому варто сказати, що це добре?)

  • Йдеться про визначення та виконання функції відразу.
  • Ви могли б зробити так, що функція самовиконання повертає значення і передає функцію як параметр іншій функції.
  • Це добре для інкапсуляції.
  • Це також добре для визначення рівня блоків.
  • Так, ви можете укласти всі свої файли .js у функцію самовиконання та запобігти забрудненню глобального простору імен. ;)

Більше тут .


43
Точка 1. Як? Пункт 2. Це зовсім інша найкраща практика. Точка 3. Яка функція не працює? 4,5,6,7. Доречність? 8. Ну, 1/8 - це не погано, мабуть.
Ерік Reppen

2
На сім років пізніше, але для пункту 1. він зовсім не зменшує код, адже він створює мінімум два рядки коду для створення функції.
YungGun

1
Єдиним моментом тут є "Це забезпечує закриття, що запобігає іменуванню конфліктів", кожен інший пункт - це переформулювання цього або помилкового. можливо, ви можете спростити свою відповідь?
pcarvalho

19

Розміщення імен. Області JavaScript є функціональними.


7
downvotes все ще надходять , тому що я розділяє простору імен замість внесення оглядового ; це питання визначення - див., наприклад, Вікіпедія : Простір імен в інформатиці (іноді також називається областю імен), це абстрактний контейнер або середовище, створене для вмісту логічного угруповання унікальних ідентифікаторів або символів (тобто імен). і Ідентифікатор простору імен може надати назву контексту (Сфера застосування інформатики), а терміни іноді використовуються як взаємозамінні.
Крістоф

5
Області функцій Javascript надають простір, у якому живуть імена змінних, простір імен ; що це анонімне, не пов’язане з ідентифікатором простору імен, не має значення ...
Крістоф

12

Я не можу повірити, що жодна з відповідей не згадує загальносвітові глобали.

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

В основному функціональний блок гарантує, що всі залежні "глобальні зміни", які ви визначили, обмежені вашою програмою, але це не захищає вас від визначення неявних глобалів. JSHint або подібне може надати рекомендації щодо захисту від такої поведінки.

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

Що стосується privateвластивостей, вони є завищеними, якщо ви не створюєте загальнодоступні рамки чи бібліотеку, але якщо вам потрібно їх реалізувати, Дуглас Крокфорд має кілька хороших ідей.


8
Суворий режим захищає від загальних глобальних. Це разом із авто-провайдером дозволило б вам покритись. Я ніколи не розумів хула над приватною власністю. Зазначте vars всередині конструктора func. Зроблено. Якщо думка забути використати «нове» ключове слово підтримує вас вночі, напишіть заводську функцію. Зроблено ще раз.
Ерік Reppen

8

Я прочитав усі відповіді, чогось дуже важливого не вистачає . Є дві основні причини, чому мені потрібні самовиконання анонімних функцій, або, краще сказати, " Виявлення негайно викликаних функцій (IIFE) ":

  1. Краще управління простором імен (Уникнення забруднення простору імен -> JS-модуль)
  2. Закриття (моделювання членів приватного класу, як відомо від OOP)

Перший був дуже добре пояснений. Для другого, будь ласка, вивчіть наступний приклад:

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префікса, тому за умовою він не повинен бути використаний з великої літери.


7

Чи є параметр і "Пучок коду" повертає функцію?

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

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


+1; Я віддаю перевагу явну var x = something;зовнішню функцію над xпараметром, однак: imo, це читабельніше таким чином ...
Крістоф

@Christoph: Якщо значення "чогось" змінюється після створення функції, то воно буде використовувати нове значення, а не те, яке було на момент створення.
stesch

@stesch: звідки ти це взяв? Наскільки я знаю, це не так; єдиний спосіб отримати реальні посилання в JS - це використовувати аргументи-об’єкт, але навіть це працює не у всіх браузерах
Крістоф,

@Christoph: "JavaScript: хороші частини", Дуглас Крокфорд (O'Reilly)
stesch

@stesch: воно не працює так, як ви описуєте: нове значення буде використано, якщо ви випадете змінну xі будете залежати безпосередньо від лексичної сфери, тобто document.write(something)...
Крістоф

6

Ізоляція сфери, можливо. Так що змінні всередині декларації функції не забруднюють зовнішній простір імен.

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


4
Що це за реалізація?
Меттью Крамлі

1
Будь-яка реалізація, не написана в суворому режимі і містить і неявну вар-декларацію, що спричиняє її глобальність.
Ерік Реппен

5

Ось вагомий приклад того, як самовикликання анонімної функції може бути корисним.

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


Ви можете пояснити трохи більше про те, що відбувається з першим набором коду
radio_head

З letзамість varпершого випадку буде добре.
Віталій Зданевич,

3

Одна відмінність полягає в тому, що змінні, які ви декларуєте у функції, локальні, тому вони виходять, коли ви виходите з функції та не конфліктуєте з іншими змінними в іншому коді.


1

Оскільки функції в Javascript є першокласним об'єктом, визначаючи його таким чином, він ефективно визначає "клас", як C ++ або C #.

Ця функція може визначати локальні змінні та мати в ній функції. Внутрішні функції (ефективні методи екземплярів) матимуть доступ до локальних змінних (фактично змінні екземпляри), але вони будуть ізольовані від решти сценарію.


1

Функція самовиклику в JavaScript:

Самовикликаючий вираз викликається (запускається) автоматично, без виклику. Самовикликаючий вираз викликається відразу після його створення. Це в основному використовується для уникнення конфліктування імен, а також для досягнення інкапсуляції. Змінні або оголошені об'єкти недоступні за межами цієї функції. Щоб уникнути проблем мінімізації (filename.min) завжди використовуйте функцію, яка виконується самостійно.


1

Функція самовиконання використовується для управління областю змінної.

Область змінної - це область вашої програми, в якій вона визначена.

Глобальна змінна має глобальний масштаб; він визначений скрізь у вашому коді JavaScript і до нього можна отримати доступ з будь-якого місця в сценарії, навіть у ваших функціях. З іншого боку, змінні, оголошені в межах функції, визначаються лише в тілі функції. Вони є локальними змінними, мають локальну область застосування і до них можна отримати доступ лише в межах цієї функції. Параметри функції також враховуються як локальні змінні та визначаються лише в тілі функції.

Як показано нижче, ви можете отримати доступ до змінної глобальної змінної всередині своєї функції, а також зазначити, що в тілі функції локальна змінна має перевагу над глобальною змінною з тим самим іменем.

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

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

scope(); 

Таким чином, функція самовиконання дозволяє писати код без занепокоєння, як називаються змінні в інших блоках коду javascript.


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

Власне, вищевказана функція буде розглядатися як вираз функції без імені.

Основна мета обгортання функції з близькими та відкритими дужками - уникнути забруднення глобального простору.

Змінні та функції всередині виразу функції стали приватними (тобто) вони не будуть доступні поза функцією.


1

Коротка відповідь: запобігання забрудненню глобальної (або вищої) сфери застосування.

IIFE (негайно викликані функції виразів) - найкраща практика для написання скриптів як плагінів, доповнень, сценаріїв користувачів або будь-яких інших сценаріїв, які очікуються для роботи зі сценаріями інших людей. . Це гарантує, що будь-яка вказана вами змінна не надає небажаних ефектів на інші сценарії.

Це інший спосіб написання виразу IIFE. Я особисто віддаю перевагу такому методу:

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

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

З наведеного вище прикладу ясно, що IIFE також може вплинути на ефективність та продуктивність, тому що функція, яка, як очікується, буде виконуватися лише один раз, буде виконана один раз і потім назавжди викинута в порожнечу . Це означає, що декларація функції або методу не залишається в пам'яті.


Добре, я раніше цього не бачив void. Мені це подобається.
Ей.

1

Спочатку ви повинні відвідати MDN IIFE , а тепер деякі моменти з цього приводу

  • це вираз негайно викликаної функції . Отже, коли ваш файл javascript викликається з HTML, ця функція викликається негайно.
  • Це запобігає доступу до змінних в ідіомі IIFE, а також забруднює глобальний обсяг.

0

Схоже, на це питання відповіли всі готові, але я все-таки опублікую свої дані.

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

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

Функція дозволяє мені використовувати деякий додатковий код для визначення атрибутів і властивостей childObjects для більш чистого коду, наприклад встановлення часто використовуваних змінних або виконання математичних рівнянь; Ой! або перевірка помилок. на відміну від обмеженості синтаксисом вкладеного об'єкта інстанції ...

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

Кодування взагалі має багато незрозумілих способів робити багато одних і тих же речей, змушуючи замислюватися: "Чому турбуватись?" Але виникають нові ситуації, коли ви більше не можете покладатися на основні / основні принципи.


0

З огляду на ваше просте запитання: "У 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 - деяка асинхронна дія.

Я не можу просто зателефонувати в очікуванні без ключового слова async при оголошенні моєї функції, і мені не потрібна названа функція для подальшого використання, але мені потрібно дочекатися цього вставлення виклику або мені потрібні інші більш багаті функції (хто знає?) .


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.