J'étudie THREE.js et j'ai remarqué un modèle où les fonctions sont définies comme suit:
var foo = ( function () {
var bar = new Bar();
return function ( ) {
//actual logic using bar from above.
//return result;
};
}());
(Exemple voir la méthode raycast ici ).
La variation normale d'une telle méthode ressemblerait à ceci:
var foo = function () {
var bar = new Bar();
//actual logic.
//return result;
};
En comparant la première version à la variante normale , la première semble différer en cela:
- Il affecte le résultat d'une fonction auto-exécutable.
- Il définit une variable locale au sein de cette fonction.
- Il renvoie la fonction réelle contenant la logique qui utilise la variable locale.
Ainsi, la principale différence est que dans la première variante, la barre n'est affectée qu'une seule fois, à l'initialisation, tandis que la seconde variante crée cette variable temporaire à chaque fois qu'elle est appelée.
Ma meilleure estimation sur la raison pour laquelle cela est utilisé est qu'il limite le nombre d'instances pour bar (il n'y en aura qu'une) et économise ainsi la gestion de la mémoire.
Mes questions:
- Cette hypothèse est-elle correcte?
- Y a-t-il un nom pour ce modèle?
- Pourquoi est-ce utilisé?
javascript
closures
iife
Patrick Klug
la source
la source
Réponses:
Vos hypothèses sont presque correctes. Passons en revue ces premiers.
Cela s'appelle une expression de fonction immédiatement invoquée ou IIFE
C'est la manière d'avoir des champs d'objet privé dans JavaScript car il ne fournit pas le
private
mot - clé ou la fonctionnalité autrement.Là encore, le point principal est que cette variable locale est privée .
AFAIK vous pouvez appeler ce modèle de modèle de module . Citant:
En comparant ces deux exemples, mes meilleures suppositions sur les raisons pour lesquelles le premier est utilisé sont:
Mais si vous avez juste besoin de l'objet vanilla à chaque fois, alors ce modèle n'ajoutera probablement aucune valeur.
la source
Il limite les coûts d'initialisation des objets et garantit en outre que toutes les invocations de fonctions utilisent le même objet. Cela permet, par exemple, de stocker l'état dans l'objet pour de futures invocations.
Bien qu'il soit possible que cela limite l'utilisation de la mémoire, généralement le GC collectera les objets inutilisés de toute façon, donc ce modèle n'aidera probablement pas beaucoup.
Ce modèle est une forme spécifique de fermeture .
la source
Je ne suis pas sûr que ce modèle ait un nom plus correct, mais cela ressemble à un module pour moi, et la raison pour laquelle il est utilisé est à la fois d'encapsuler et de maintenir l'état.
La fermeture (identifiée par une fonction dans une fonction) garantit que la fonction interne a accès aux variables de la fonction externe.
Dans l'exemple que vous avez donné, la fonction interne est renvoyée (et affectée à
foo
) en exécutant la fonction externe, ce qui signifie qu'elletmpObject
continue à vivre dans la fermeture et que plusieurs appels à la fonction internefoo()
opèrent sur la même instance detmpObject
.la source
La principale différence entre votre code et le code Three.js est que dans le code Three.js, la variable
tmpObject
n'est initialisée qu'une seule fois, puis partagée par chaque appel de la fonction retournée.Cela serait utile pour conserver un état entre les appels, de la même manière que les
static
variables sont utilisées dans les langages de type C.tmpObject
est une variable privée uniquement visible par la fonction interne.Il modifie l'utilisation de la mémoire, mais il n'est pas conçu pour économiser de la mémoire.
la source
J'aimerais contribuer à ce sujet intéressant en étendant au concept du modèle de module révélateur, qui garantit que toutes les méthodes et variables restent privées jusqu'à ce qu'elles soient explicitement exposées.
Dans ce dernier cas, la méthode d'addition serait appelée comme Calculator.add ();
la source
Dans l'exemple fourni, le premier extrait de code utilisera la même instance de tmpObject pour chaque appel à la fonction foo (), où comme dans le deuxième extrait de code, tmpObject sera une nouvelle instance à chaque fois.
L'une des raisons pour lesquelles le premier extrait de code a pu être utilisé est que la variable tmpObject peut être partagée entre les appels à foo (), sans que sa valeur ne soit divulguée dans la portée dans laquelle foo () est déclarée.
La version de fonction non exécutée immédiatement du premier extrait de code ressemblerait en fait à ceci:
Notez cependant que cette version a tmpObject dans la même portée que foo (), donc il pourrait être manipulé plus tard.
Une meilleure façon d'obtenir la même fonctionnalité serait d'utiliser un module séparé:
Module 'foo.js':
Module 2:
Une comparaison entre les performances d'un IEF et d'une fonction de créateur foo nommée: http://jsperf.com/ief-vs-named-function
la source