Was ist der Zweck einer selbstausführenden Funktion in Javascript?

427

Wann möchten Sie in Javascript Folgendes verwenden:

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

darüber:

//Bunch of code...
Ej.
quelle
3
Schauen Sie sich auch eine ( technische ) Erklärung an und hier . Lesen Sie für die Syntax, warum die Klammern erforderlich sind und wohin sie gehen sollen .
Bergi
Warum stehen die letzten beiden Klammern kurz vor dem Semikolon?
Johnny
3
@johnny der Teil vor diesen beiden letzten Klammern deklariert eine (anonyme) Funktion. Diese beiden Klammern rufen die Funktion auf.
Ej.
7
"Sofort aufgerufener Funktionsausdruck" oder IIFE ist hierfür ein besserer Name .
Flimm

Antworten:

404

Es geht um variables Scoping. In der selbstausführenden Funktion deklarierte Variablen sind standardmäßig nur für Code innerhalb der selbstausführenden Funktion verfügbar. Auf diese Weise kann Code geschrieben werden, ohne dass es darauf ankommt, wie Variablen in anderen JavaScript-Codeblöcken benannt werden.

Zum Beispiel, wie in einem Kommentar von Alexander erwähnt :

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

console.log(foo);

Dies wird zuerst protokolliert 3und dann beim nächsten einen Fehler auslösen, console.logda dieser foonicht definiert ist.

Ken Browning
quelle
7
Und auch zum Nutzen vieler Leute da draußen, einschließlich einer ganzen Reihe von Netflix-Ingenieuren: ES IST NUR EINE FUNKTION. Es ist an und für sich nicht repräsentativ für eine Schließung. Manchmal werden Auto-Invoker in Verbindung mit schließungsrelevanten Szenarien verwendet, um ordentliche Dinge zu erledigen. Wenn Sie jedoch nicht sehen, dass etwas an einer Referenz festhält, die in einer Sprache ohne Schließung gesammelt und verschwunden ist, hat dies nichts zu tun freaking do with CLOSURES.
Erik Reppen
2
Das heißt also, es wird meistens mit Verschluss verwendet?
Pir Abdul
@AlexanderBird, nicht ganz richtig ... wenn Sie darauf verzichten var, so : ...function(){ foo=3;}? Es würde eine globale Variable setzen, oder?
T.Todua
2
@ AlexanderBird, aber das passiert bereits in lokalen Variablen innerhalb von Funktionen: function(){ var foo = 3; alert(foo); }; alert(foo);Also ich verstehe es immer noch nicht
João Pimentel Ferreira
Ah, ich verstehe, Sie erreichen alle diese 3 Funktionen gleichzeitig: 1) Sie führen die Funktion aus, indem Sie sie nur deklarieren; 2) Wie jede Funktion ist der Variablenbereich nur lokal; und 3) Die Funktion könnte anonym sein und den Hauptbereich nicht verschmutzen
João Pimentel Ferreira
94

Simpel. So ganz normal aussehend, es ist fast beruhigend:

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

Was ist jedoch, wenn ich meiner Seite eine wirklich praktische Javascript-Bibliothek hinzufüge, die erweiterte Zeichen in ihre Darstellungen auf Basisebene übersetzt?

Warte was?

Ich meine, wenn jemand ein Zeichen mit einem Akzent eingibt, aber ich möchte nur 'englische' Zeichen AZ in meinem Programm? Nun ... die spanischen 'ñ' und französischen 'é' Zeichen können in Basiszeichen von 'n' und 'e' übersetzt werden.

Also hat jemand eine nette Person einen umfassenden Zeichenkonverter geschrieben, den ich in meine Site aufnehmen kann ... ich füge ihn hinzu.

Ein Problem: Es enthält eine Funktion namens "Name", die mit meiner Funktion identisch ist.

Dies nennt man Kollision. Wir haben zwei Funktionen im selben Bereich mit demselben Namen deklariert . Das wollen wir vermeiden.

Also müssen wir unseren Code irgendwie erweitern.

Die einzige Möglichkeit, Code in Javascript zu erfassen, besteht darin, ihn in eine Funktion zu verpacken:

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

Das könnte unser Problem lösen. Alles ist jetzt geschlossen und nur über unsere Öffnungs- und Schließstreben zugänglich.

Wir haben eine Funktion in einer Funktion ... die seltsam anzusehen ist, aber völlig legal.

Nur ein Problem. Unser Code funktioniert nicht. Unsere userName-Variable wird niemals in die Konsole übernommen!

Wir können dieses Problem lösen, indem wir unserer Funktion nach unserem vorhandenen Codeblock einen Aufruf hinzufügen ...

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();

Oder davor!

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

Ein sekundäres Problem: Wie hoch ist die Wahrscheinlichkeit, dass der Name 'main' noch nicht verwendet wurde? ... so sehr, sehr schlank.

Wir brauchen mehr Scoping. Und eine Möglichkeit, unsere main () - Funktion automatisch auszuführen.

Jetzt kommen wir zu Funktionen für die automatische Ausführung (oder selbstausführend, selbstlaufend, was auch immer).

((){})();

Die Syntax ist als Sünde umständlich. Es funktioniert jedoch.

Wenn Sie eine Funktionsdefinition in Klammern wickeln und eine Parameterliste ( einen anderen Satz oder Klammern!) Wirkt es als Funktion Anruf .

Schauen wir uns also noch einmal unseren Code mit einer selbstausführenden Syntax an:

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

    console.log(name());

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

In den meisten Tutorials, die Sie lesen, werden Sie jetzt mit dem Begriff "anonyme Selbstausführung" oder ähnlichem bombardiert.

Nach vielen Jahren der beruflichen Entwicklung, ich stark fordere Sie zu nennen jede Funktion , die Sie schreiben für Debugging - Zwecke.

Wenn etwas schief geht (und es wird), überprüfen Sie die Rückverfolgung in Ihrem Browser. Es ist immer einfacher, Ihre Codeprobleme einzugrenzen, wenn die Einträge im Stack-Trace Namen haben!

Sehr langatmig und ich hoffe es hilft!

Sean Holden
quelle
2
Vielen Dank :) Ich habe rund um das Internet gesucht, um die Vorteile von IIFE in Bezug auf normale Funktionen in Bezug auf variable Privatsphäre zu verstehen, und Ihre Antwort ist einfach die beste. Jeder sagt, dass einer der besten Vorteile darin besteht, dass die Variablen und Funktionen in IIFE "endlich" privat sind, wenn eine normale Funktion Ihnen genau das Gleiche bietet. Schließlich denke ich, dass ich es durch Ihren Erklärungsprozess bekommen habe. IIFE ist schließlich nur eine Funktion, aber jetzt verstehe ich, warum ich sie verwenden soll. Nochmals vielen Dank!
viery365
Vielen Dank, dass Sie sich die Zeit genommen haben, dies so gut zu erklären.
MSC
Gute Antwort. Ich habe jedoch eine Frage zu Ihrem letzten Punkt: Wenn Sie empfehlen, alle Funktionen zu benennen, sagen Sie dann, dass es eine Möglichkeit gibt, dies mit selbstausführenden Funktionen zu tun, oder schlagen Sie vor, dass jeder die Funktion benennt und sie dann aufruft? EDIT Oh, ich verstehe. Dieser ist bereits benannt. Duh. Vielleicht möchten Sie darauf hinweisen, dass Sie die Verwendung einer benannten selbstausführenden Funktion rechtfertigen.
FireSBurnsmuP
Nun mein Freund, das ist DIE Antwort, nach der ich gesucht habe:)
João Pimentel Ferreira
Dies ist die Antwort, nach der ich gesucht habe, nicht die, die als akzeptiert markiert ist. Habe ich Recht, wenn ich sage, dass es nicht um die Kollision von Variablennamen geht , sondern um die Kollision von Funktionsnamen ? Variablen in selbst normalen Nicht-Iife-Funktionen sind lokal begrenzt und kollidieren nicht mit globalen Variablen, nicht wahr?
Kumar Manish
32

Selbstaufruf (auch als automatischer Aufruf bezeichnet) ist, wenn eine Funktion unmittelbar nach ihrer Definition ausgeführt wird. Dies ist ein Kernmuster und dient als Grundlage für viele andere Muster der JavaScript-Entwicklung.

Ich bin ein großer Fan :) davon, weil:

  • Es hält den Code auf ein Minimum
  • Es erzwingt die Trennung von Verhalten und Präsentation
  • Es bietet einen Abschluss, der Namenskonflikte verhindert

Enorm - (Warum solltest du sagen, dass es gut ist?)

  • Es geht darum, eine Funktion gleichzeitig zu definieren und auszuführen.
  • Diese selbstausführende Funktion könnte einen Wert zurückgeben und die Funktion als Parameter an eine andere Funktion übergeben.
  • Es ist gut für die Kapselung.
  • Es ist auch gut für Block Scoping.
  • Ja, Sie können alle Ihre .js-Dateien in eine selbstausführende Funktion einschließen und die Verschmutzung des globalen Namespace verhindern. ;)

Mehr hier .

MA Hossain Tonu
quelle
43
Punkt 1. Wie? Punkt 2. Das ist eine ganz andere Best Practice. Punkt 3. Welche Funktion funktioniert nicht? 4,5,6,7. Relevanz? 8. Nun, 1/8 ist nicht schlecht, denke ich.
Erik Reppen
2
Sieben Jahre zu spät, aber für Punkt 1 wird der Code überhaupt nicht reduziert. Tatsächlich werden beim Erstellen der Funktion mindestens zwei Codezeilen hinzugefügt.
YungGun
1
Der einzige Punkt hier ist "Es bietet einen Abschluss, der Namenskonflikte verhindert". Jeder andere Punkt formuliert dies neu oder falsch. Vielleicht können Sie Ihre Antwort vereinfachen?
Pcarvalho
19

Namensraum. Die Bereiche von JavaScript sind auf Funktionsebene.

Christoph
quelle
7
Downvotes kommen immer noch, weil ich Namespace- Instad of Scoping verwendet habe ; Dies ist eine Frage der Definition - siehe z. B. Wikipedia : Ein Namespace in der Informatik (manchmal auch als Namensbereich bezeichnet) ist ein abstrakter Container oder eine Umgebung, die eine logische Gruppierung eindeutiger Bezeichner oder Symbole (dh Namen) enthält. und Eine Namespace-ID kann einen Kontext (Scope in Computer Science) für einen Namen bereitstellen, und die Begriffe werden manchmal synonym verwendet.
Christoph
5
Die Bereiche auf Funktionsebene von Javascript bieten den Bereich, in dem Variablennamen leben, einen Namespace . dass es sich um eine anonyme handelt, die nicht mit einer Namespace-ID verknüpft ist, ist irrelevant ...
Christoph
12

Ich kann nicht glauben, dass keine der Antworten implizite Globale erwähnt.

Das (function(){})()Konstrukt schützt nicht vor impliziten Globalen, was für mich das größere Problem ist, siehe http://yuiblog.com/blog/2006/06/01/global-domination/

Grundsätzlich stellt der Funktionsblock sicher, dass alle von Ihnen definierten abhängigen "globalen Variablen" auf Ihr Programm beschränkt sind. Er schützt Sie nicht vor der Definition impliziter globaler Variablen. JSHint oder ähnliches kann Empfehlungen zur Abwehr dieses Verhaltens geben.

Die präzisere var App = {}Syntax bietet ein ähnliches Schutzniveau und kann auf 'öffentlichen' Seiten in den Funktionsblock eingeschlossen werden. (siehe Ember.js oder SproutCore für reale Welt Beispiele für Bibliotheken , die dieses Konstrukt verwenden)

Soweit privateEigenschaften gehen, sind sie Art von hoch genug , wenn Sie einen öffentlichen Rahmen oder Bibliothek erstellen, aber wenn man sie umsetzen müssen, Douglas Crockford einige gute Ideen hat.

David W. Keith
quelle
8
Der strikte Modus schützt vor impliziten Globalen. Das in Verbindung mit einem Auto-Invoker hätte Sie abgedeckt. Ich habe den Hooplah über Privateigentum nie verstanden. Deklarieren Sie vars in einem func-Konstruktor. Erledigt. Wenn der Gedanke, die Verwendung des Schlüsselworts 'new' zu vergessen, Sie nachts wach hält, schreiben Sie eine Factory-Funktion. Wieder fertig.
Erik Reppen
8

Ich habe alle Antworten gelesen, hier fehlt etwas sehr Wichtiges , ich werde KÜSSEN. Es gibt zwei Hauptgründe, warum ich selbstausführende anonyme Funktionen oder besser gesagt " Sofort aufgerufener Funktionsausdruck (IIFE) " benötige :

  1. Bessere Namespace-Verwaltung (Vermeidung von Namespace-Verschmutzung -> JS-Modul)
  2. Schließungen (Simulation von Mitgliedern der Privatklasse, wie von OOP bekannt)

Der erste wurde sehr gut erklärt. Für das zweite studieren Sie bitte folgendes Beispiel:

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

Achtung 1: Wir weisen keine Funktion zu MyClosureObject, sondern das Ergebnis des Aufrufs dieser Funktion . Beachten Sie ()in der letzten Zeile.

Achtung 2: Was Sie zusätzlich über Funktionen in Javascript wissen müssen, ist, dass die inneren Funktionen Zugriff auf die Parameter und Variablen erhalten der Funktionen erhalten, in denen sie definiert sind.

Versuchen wir einige Experimente:

Ich kann es MyNamebenutzen getMyNameund es funktioniert:

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

Der folgende geniale Ansatz würde nicht funktionieren:

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

Aber ich kann einen anderen Namen setzen und das erwartete Ergebnis erhalten:

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

Bearbeiten: Im obigen Beispiel MyClosureObjectist die Verwendung ohne newPräfix vorgesehen, daher sollte es gemäß Konvention nicht großgeschrieben werden.

Einsam
quelle
7

Gibt es einen Parameter und der "Codebündel" gibt eine Funktion zurück?

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

Schließung. Der Wert von somethingwird von der zugewiesenen Funktion verwendet a. somethingkönnte einen variierenden Wert haben (for-Schleife) und jedes Mal, wenn a eine neue Funktion hat.

stesch
quelle
+1; Ich bevorzuge jedoch eine explizite var x = something;Funktion in der äußeren Funktion xals Parameter: imo ist es auf diese Weise besser lesbar ...
Christoph
@Christoph: Wenn sich der Wert von "etwas" nach der Erstellung der Funktion ändert, wird der neue Wert verwendet und nicht der zum Zeitpunkt der Erstellung.
stesch
@stesch: woher hast du das? Soweit ich weiß, ist das nicht der Fall; Die einzige Möglichkeit, echte Referenzen in JS zu erhalten, ist die Verwendung des Argument-Objekts, aber selbst das funktioniert nicht in allen Browsern
Christoph
@Christoph: "JavaScript: Die guten Teile", Douglas Crockford (O'Reilly)
stesch
@stesch: Es funktioniert nicht so, wie Sie es beschreiben: Der neue Wert wird verwendet, wenn Sie die Variable xdocument.write(something)
Christoph
6

Umfang Isolation vielleicht. Damit die Variablen in der Funktionsdeklaration den äußeren Namespace nicht verschmutzen.

Natürlich werden sie es bei der Hälfte der JS-Implementierungen sowieso tun.

Chaos
quelle
4
Welche Implementierungen wären das?
Matthew Crumley
1
Jede Implementierung, die nicht im strengen Modus geschrieben wurde und eine implizite var-Deklaration enthält, die dazu führt, dass sie global ist.
Erik Reppen
5

Hier ist ein gutes Beispiel dafür, wie eine selbst aufrufende anonyme Funktion nützlich sein kann.

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

Ausgabe: 10, 10, 10, 10, 10...

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

Ausgabe: 0, 1, 2, 3, 4...

sg.cc.
quelle
Können
Mit letanstelle des varersten Falles wird alles in Ordnung sein.
Vitaly Zdanevich
3

Ein Unterschied besteht darin, dass die Variablen, die Sie in der Funktion deklarieren, lokal sind, sodass sie beim Beenden der Funktion verschwinden und nicht mit anderen Variablen in anderem Code in Konflikt stehen.

Guffa
quelle
1

Da Funktionen in Javascript erstklassige Objekte sind, definiert es auf diese Weise effektiv eine "Klasse", ähnlich wie C ++ oder C #.

Diese Funktion kann lokale Variablen definieren und Funktionen enthalten. Die internen Funktionen (effektiv Instanzmethoden) haben Zugriff auf die lokalen Variablen (effektiv Instanzvariablen), sind jedoch vom Rest des Skripts isoliert.

James Curran
quelle
1

Selbstaufgerufene Funktion in Javascript:

Ein selbst aufrufender Ausdruck wird automatisch aufgerufen (gestartet), ohne aufgerufen zu werden. Ein selbst aufrufender Ausdruck wird direkt nach seiner Erstellung aufgerufen. Dies wird im Wesentlichen verwendet, um Namenskonflikte zu vermeiden und um eine Kapselung zu erreichen. Auf die Variablen oder deklarierten Objekte kann außerhalb dieser Funktion nicht zugegriffen werden. Verwenden Sie zur Vermeidung von Minimierungsproblemen (Dateiname.min) immer die selbst ausgeführte Funktion.

Kishor Vitekar
quelle
1

Selbstausführende Funktionen werden verwendet, um den Bereich einer Variablen zu verwalten.

Der Bereich einer Variablen ist der Bereich Ihres Programms, in dem sie definiert ist.

Eine globale Variable hat einen globalen Gültigkeitsbereich. Es ist überall in Ihrem JavaScript-Code definiert und kann von überall im Skript aufgerufen werden, auch in Ihren Funktionen. Andererseits werden Variablen, die innerhalb einer Funktion deklariert sind, nur innerhalb des Funktionskörpers definiert. Sie sind lokale Variablen, haben einen lokalen Gültigkeitsbereich und können nur innerhalb dieser Funktion aufgerufen werden. Funktionsparameter gelten auch als lokale Variablen und werden nur innerhalb des Funktionskörpers definiert.

Wie unten gezeigt, können Sie auf die globale Variablenvariable in Ihrer Funktion zugreifen und beachten, dass innerhalb des Funktionskörpers eine lokale Variable Vorrang vor einer globalen Variablen mit demselben Namen hat.

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(); 

Grundsätzlich ermöglicht eine selbstausführende Funktion das Schreiben von Code, ohne sich darum zu kümmern, wie Variablen in anderen Blöcken von Javascript-Code benannt werden.

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

Tatsächlich wird die obige Funktion als Funktionsausdruck ohne Namen behandelt.

Der Hauptzweck des Umschließens einer Funktion in enge und offene Klammern besteht darin, eine Verschmutzung des globalen Raums zu vermeiden.

Die Variablen und Funktionen innerhalb des Funktionsausdrucks wurden privat (dh sie sind außerhalb der Funktion nicht verfügbar.

Madhankumar
quelle
1

Die kurze Antwort lautet: Verhinderung der Verschmutzung des globalen (oder höheren) Bereichs.

IIFE (Sofort aufgerufene Funktionsausdrücke) ist die beste Methode zum Schreiben von Skripten als Plug-Ins, Add-Ons, Benutzerskripten oder von Skripten, von denen erwartet wird, dass sie mit Skripten anderer Personen funktionieren . Dies stellt sicher, dass jede von Ihnen definierte Variable keine unerwünschten Auswirkungen auf andere Skripte hat.

Dies ist die andere Möglichkeit, einen IIFE-Ausdruck zu schreiben. Ich persönlich bevorzuge diese folgende Methode:

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

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

Aus dem obigen Beispiel geht klar hervor, dass IIFE auch die Effizienz und Leistung beeinflussen kann, da die Funktion, von der erwartet wird, dass sie nur einmal ausgeführt wird, einmal ausgeführt und dann endgültig in den Hohlraum geworfen wird . Dies bedeutet, dass die Funktions- oder Methodendeklaration nicht im Speicher verbleibt.

Donovan P.
quelle
Schön, ich hatte diese Verwendung noch nie gesehen void. Ich mag das.
Ej.
1

Zuerst müssen Sie MDN IIFE besuchen . Nun einige Punkte dazu

  • Dies ist der sofort aufgerufene Funktionsausdruck . Wenn Ihre Javascript-Datei aus HTML aufgerufen wird, wird diese Funktion sofort aufgerufen.
  • Dies verhindert den Zugriff auf Variablen innerhalb der IIFE-Sprache und verschmutzt den globalen Bereich.
JustIn
quelle
0

Es sieht so aus, als ob diese Frage fertig beantwortet wurde, aber ich werde trotzdem meine Eingabe posten.

Ich weiß, wann ich selbstausführende Funktionen verwenden möchte.

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

Mit dieser Funktion kann ich zusätzlichen Code verwenden, um die childObjects-Attribute und -Eigenschaften für saubereren Code zu definieren, z. B. das Festlegen häufig verwendeter Variablen oder das Ausführen mathematischer Gleichungen. Oh! oder Fehlerprüfung. im Gegensatz zu beschränkt auf die Instanziierungssyntax für verschachtelte Objekte von ...

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

Das Codieren im Allgemeinen hat viele dunkle Möglichkeiten, viele der gleichen Dinge zu tun, und Sie fragen sich: "Warum sich die Mühe machen?" Es tauchen jedoch immer wieder neue Situationen auf, in denen Sie sich nicht mehr nur auf die Grundprinzipien verlassen können.

Garrett
quelle
0

Angesichts Ihrer einfachen Frage: "Wann möchten Sie in Javascript Folgendes verwenden: ..."

Ich mag die Antworten von @ken_browning und @ sean_holding, aber hier ist ein weiterer Anwendungsfall, den ich nicht erwähnt sehe:

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());

Dabei ist Node.insert eine asynchrone Aktion.

Ich kann nicht einfach warten ohne das asynchrone Schlüsselwort bei der Deklaration meiner Funktion aufrufen, und ich brauche keine benannte Funktion für die spätere Verwendung, sondern muss auf diesen Einfügeaufruf warten oder ich brauche einige andere umfangreichere Funktionen (wer weiß?) .

zentechinc
quelle
-3

Mit IIRC können Sie private Eigenschaften und Methoden erstellen.

Ólafur Waage
quelle