Ich studiere THREE.js und habe ein Muster festgestellt, in dem Funktionen wie folgt definiert sind:
var foo = ( function () {
var bar = new Bar();
return function ( ) {
//actual logic using bar from above.
//return result;
};
}());
(Beispiel siehe Raycast-Methode hier ).
Die normale Variante einer solchen Methode würde folgendermaßen aussehen:
var foo = function () {
var bar = new Bar();
//actual logic.
//return result;
};
Vergleicht man die erste Version mit der normalen Variante, so scheint sich die erste darin zu unterscheiden:
- Es weist das Ergebnis einer selbstausführenden Funktion zu.
- Es definiert eine lokale Variable innerhalb dieser Funktion.
- Es gibt die eigentliche Funktion zurück, die die Logik enthält, die die lokale Variable verwendet.
Der Hauptunterschied besteht also darin, dass in der ersten Variante der Balken bei der Initialisierung nur einmal zugewiesen wird, während die zweite Variante diese temporäre Variable bei jedem Aufruf erstellt.
Meine beste Vermutung, warum dies verwendet wird, ist, dass es die Anzahl der Instanzen für Balken begrenzt (es wird nur eine geben) und somit Speicherverwaltungsaufwand spart.
Meine Fragen:
- Ist diese Annahme richtig?
- Gibt es einen Namen für dieses Muster?
- Warum wird das verwendet?
javascript
closures
iife
Patrick Klug
quelle
quelle
Antworten:
Ihre Annahmen sind fast richtig. Lassen Sie uns diese zuerst überprüfen.
Dies wird als sofort aufgerufener Funktionsausdruck oder IIFE bezeichnet
Auf diese Weise können private Objektfelder in JavaScript verwendet werden, da das
private
Schlüsselwort oder die Funktionalität nicht anderweitig bereitgestellt werden.Auch hier ist der Hauptpunkt, dass diese lokale Variable privat ist .
AFAIK können Sie dieses Muster nennen Modul Muster . Zitat:
Wenn ich diese beiden Beispiele vergleiche, sind meine besten Vermutungen darüber, warum das erste verwendet wird, folgende:
Wenn Sie jedoch jedes Mal nur das Vanilleobjekt benötigen, wird dieses Muster wahrscheinlich keinen Wert hinzufügen.
quelle
Es begrenzt die Objektinitialisierungskosten und stellt zusätzlich sicher, dass alle Funktionsaufrufe dasselbe Objekt verwenden. Auf diese Weise kann beispielsweise der Status im Objekt gespeichert werden, damit zukünftige Aufrufe verwendet werden können.
Während es möglich ist, dass es die Speichernutzung einschränkt, sammelt der GC normalerweise sowieso nicht verwendete Objekte, so dass dieses Muster wahrscheinlich nicht viel hilft.
Dieses Muster ist eine spezielle Form des Verschlusses .
quelle
Ich bin nicht sicher, ob dieses Muster einen korrekteren Namen hat, aber dies sieht für mich wie ein Modul aus, und der Grund, warum es verwendet wird, besteht darin, den Status sowohl zu kapseln als auch beizubehalten.
Der Abschluss (identifiziert durch eine Funktion innerhalb einer Funktion) stellt sicher, dass die innere Funktion Zugriff auf die Variablen innerhalb der äußeren Funktion hat.
In dem von Ihnen angegebenen Beispiel wird die innere Funktion
foo
durch Ausführen der äußeren Funktion zurückgegeben (und zugewiesen ), was bedeutet, dass sietmpObject
weiterhin innerhalb des Abschlusses lebt und mehrere Aufrufe der inneren Funktionfoo()
für dieselbe Instanz von ausgeführt werdentmpObject
.quelle
Der Hauptunterschied zwischen Ihrem Code und dem Three.js-Code besteht darin, dass die Variable im Three.js-Code
tmpObject
nur einmal initialisiert und dann von jedem Aufruf der zurückgegebenen Funktion gemeinsam genutzt wird.Dies wäre nützlich, um einen bestimmten Status zwischen Aufrufen beizubehalten, ähnlich wie
static
Variablen in C-ähnlichen Sprachen verwendet werden.tmpObject
ist eine private Variable, die nur für die innere Funktion sichtbar ist.Es ändert die Speichernutzung, ist jedoch nicht zum Speichern von Speicher ausgelegt.
quelle
Ich möchte zu diesem interessanten Thread beitragen, indem ich mich auf das Konzept des aufschlussreichen Modulmusters ausdehne, das sicherstellt, dass alle Methoden und Variablen privat bleiben, bis sie explizit verfügbar gemacht werden.
Im letzteren Fall würde die Additionsmethode als Calculator.add () aufgerufen;
quelle
In dem bereitgestellten Beispiel verwendet das erste Snippet für jeden Aufruf der Funktion foo () dieselbe Instanz von tmpObject, wobei tmpObject wie im zweiten Snippet jedes Mal eine neue Instanz ist.
Ein Grund, warum das erste Snippet möglicherweise verwendet wurde, besteht darin, dass die Variable tmpObject von Aufrufen von foo () gemeinsam genutzt werden kann, ohne dass ihr Wert in den Bereich gelangt, in dem foo () deklariert ist.
Die nicht sofort ausgeführte Funktionsversion des ersten Snippets würde tatsächlich so aussehen:
Beachten Sie jedoch, dass diese Version tmpObject im selben Bereich wie foo () hat, sodass es später bearbeitet werden kann.
Ein besserer Weg, um die gleiche Funktionalität zu erreichen, wäre die Verwendung eines separaten Moduls:
Modul 'foo.js':
Modul 2:
Ein Vergleich zwischen der Leistung eines IEF und einer benannten foo-Erstellerfunktion: http://jsperf.com/ief-vs-named-function
quelle