Muster
(function (foo) {
...Code...
foo.bar = baz;
...More Code...
}(window.FOO = window.FOO || {});
Es gibt keinen formalen Namen für das von Ihnen beschriebene Muster, da es sich um drei separate Muster handelt, die kombiniert sind. Jedes Muster hat mehrere Namen, aber in diesem Beitrag verwende ich folgende Terminologie:
- Verschluss
- Alias
- Namespace-Erweiterung
Verschluss
Die Grundlage des gesamten Musters ist der Verschluss
. Es handelt sich einfach um eine Funktion, die verwendet wird, um Variablen und Funktionen zu schützen, so dass sie nicht den globalen Namensraum verschmutzen:
Kein Verschluss
// diese deklarieren window.foo und window.bar jeweils
// als solche verschmutzen sie den globalen Namensraum
var foo;
function bar() {}
Verschluss, in diesem Fall ein <a href="http://benalman.com/news/2010/11/immediately-invoked-function-expression/">Sofort eingefügte Funktionsausdruck (IIFE)</a>
(function () {
// diese deklarieren foo und bar innerhalb der Funktion
// aber sie sind außerhalb der Funktion nicht zugänglich
var foo;
function bar() {}
}());
Der Vorteil, Variablen innerhalb eines Verschlusses zu halten, besteht darin, dass Sie sich keine Sorgen darüber machen müssen, dass jemand die von Ihnen verwendeten Variablen überschreibt. Dies ist besonders wichtig für temporäre Variablen wie i
oder j
, die häufig verwendet werden.
Alias
Der zweite wichtige Teil dieses Musters ist die Aliasbildung. Durch die Aliasbildung kann eine Variable innerhalb eines Verschlusses definiert und verwendet werden, ohne sich darum kümmern zu müssen, in welchem globalen Namensraum sie sich befindet.
Ohne Aliasbildung
(function () {
...
foo = window.SomeFunction(bar, baz);
...
}());
Mit Aliasbildung
(function (sf) { //lokaler Name
...
foo = sf(bar, baz);
...
}(window.SomeFunction)); //globaler Namensraum
Dies ist besonders wichtig, denn dadurch kann der globale Namensraum in einer großen JavaScript-Datei geändert werden, indem der Name an einer einzigen Stelle geändert wird. Dies ist Eine gute Sache™. Darüber hinaus können Minifizierer den internen Alias auf einen einzelnen Buchstabenvariablennamen wie a
verkürzen, was bei der Minifizierung zu erheblichen Einsparungen an Bytes führt.
Namespace-Erweiterung
Das Muster der Namespace-Erweiterung basiert auf dem Zusammenführenverhalten des Oder-Operators (||
). In vielen Sprachen geben &&
und ||
entweder true
oder false
zurück, aber in JavaScript gibt &&
den ersten falsey
-Wert zurück (false
, 0
, ''
, null
, undefined
), und ||
gibt den ersten truthy
-Wert zurück (alles, was nicht falsey
ist). Für beide Operatoren wird bei einer nicht gefundenen Art der letzte Argument zurückgegeben. Dies macht den ||
-Operator zu einer bequemen Möglichkeit, einen neuen Namespace nur dann zu definieren, wenn er noch nicht vorhanden ist.
Ohne Namespace-Erweiterung
if (typeof window.Foo === 'undefined') {
window.foo = {};
}
Mit Namespace-Erweiterung
window.foo = window.foo || {};
Dies ist nützlich, da es erlaubt, einen Namespace mit zusätzlichen Eigenschaften und Methoden zu erweitern, ohne sich Gedanken darüber machen zu müssen, in welcher Reihenfolge die Eigenschaften und Methoden definiert wurden.
In diesem ersten Beispiel müsste FileA
vor FileB
ausgeführt werden:
FileA.js
window.foo = {};
window.foo.bar = 'baz';
FileB.js
window.foo.fizz = 'buzz';
In diesem zweiten Beispiel könnten File1
und File2
in beliebiger Reihenfolge ausgeführt werden:
File1.js
window.foo = window.foo || {};
window.foo.bar = 'baz';
File2.js
window.foo = window.foo || {};
window.foo.fizz = 'buzz';
Alles zusammen
Die Verwendung jedes Musters zusammen schafft ein sehr leistungsfähiges modulares Skript:
// benutze foo intern, damit du dir keine Sorgen darüber machen musst,
// wie der globale Namensraum heißt
(function (foo) {
// deklariere Variablen intern, die du lokal im Skript behalten möchtest
var i,
len,
intern,
qux;
// deklariere Funktionen/Eigenschaften des Alias, wenn du sie freigeben möchtest
foo.bar = function () {...};
// erweitere den globalen Namensraum, damit bestehende Erweiterungen erhalten bleiben
}(window.FOO = window.FOO || {}));