2010-07-28 8 views
1

J'écris du code Javascript et j'ai besoin de garder une trace d'un état global. L'état n'est jamais modifié que par une seule fonction, mais il doit être largement accessible depuis d'autres fonctions.Y at-il quelque chose de mal à attacher une variable à une fonction en Javascript?

que je fais actuellement de cette manière:


function foo(bar) { 
    var self = arguments.callee; 
    if (!self.state) { 
     self.state = 0; // called 0 times 
    } else { 
     self.state++; // increase the number of times i've been called 
    } 
} 

Est-il judicieux de lier la variable globale de l'Etat à la fonction comme celui-ci? C'est génial mais je crains qu'il y ait quelque chose de dangereux que j'ai manqué.

Répondre

2

Il n'y a rien de mal à attribuer à des propriétés des objets fonctions. Ce dont vous devez vous inquiéter, c'est que le arguments.callee est obsolète dans ECMAScript 5, qui est la spécification de langage la plus récente qui fait actuellement son chemin dans les navigateurs grand public. En mode strict, en se référant à arguments.callee donnera une erreur.

1

C'est bon. Les gens le font tout le temps avec des fonctions constructeurs. Un exemple intégré serait String.fromCharCode

Si toutefois d'autres fonctions ne doivent pas nécessairement faire référence à l'état, je préférerais faire ce qui suit:

var foo = (function() { 
    var state = 0; 
    return function (bar) { 
    state++; 
    }; 
})(); 

Même si elles ne doivent faire référence, je voudrais probablement essayer de faire fonctionner le code ci-dessus d'une manière ou d'une autre. Ou même utiliser des objets et éviter l'utilisation singleton-like.

1

J'ai fait des choses comme ça avant. Je pense que c'est un peu désordonné, mais ça ne provoquera pas la troisième guerre mondiale. Au lieu de cela, pourriez-vous définir cette fonction à l'intérieur d'une fermeture, et avoir la variable 'state' locale à cette fermeture?

var foo = (function() { 
    var state = 0; 
    return function(bar) { 
    state++; 
    }; 
}()); 

foo(bar); 
+1

L'OP dit que la variable d'état doit être accessible à partir d'autres fonctions. Vous pourriez ajouter un "getter" accessible via la fonction interne, mais ce serait désordonné. –

+0

J'ai supposé que la valeur de retour de foo (bar) serait, ou incorporerait, l'état. Notez que ni l'OP ni mon exemple montrent que foo (bar) renvoie une valeur mais vous pouvez l'imaginer. – thomasrutter

+0

Donc, vous auriez besoin d'invoquer la fonction juste pour lire l'état? Que faire si la fonction inclut d'autres effets secondaires (tels que l'incrémentation du compteur d'appels, juste pour les démarreurs)? –

1

Il est très bien, sauf que votre variable d'état ne sera jamais> 0. Essayez ceci:

function foo(bar) { 
    var self = arguments.callee; 
    if (!self.state) { // Or, as trinithis suggested: if (self.state === undefined) { 
     self.state = 1; // called once 
    } else { 
     self.state++; // increase the number of times i've been called 
    } 
} 
+0

Ah, bonne prise. Ce n'est pas vraiment le code que j'utilise, mais vous avez les yeux tranchants. –

+1

Oh je vois. Je préfèrerais plutôt utiliser 'if (self.state === undefined)'. –

+0

Le point est que! Self.state évalue à 1 si self.state vaut 0, donc vous n'obtiendrez jamais la partie "else" de la logique. –

1

Plutôt qu'un champ public, vous pouvez rendre le compteur en lecture seule. En supposant que vous voulez compter les appels à fonctions multiples, vous pouvez même définir une méthode d'utilité pour envelopper fonctions avec ce comportement:

function countCallsToFunc(func) { 
    var count = 0; 
    var self = function() { 
    count++; 
    func.apply(this, arguments); 
    }; 
    self.getCount = function() { 
    return count; 
    }; 
    return self; 
} 

var foo = countCallsToFunc(function(bar) { 
    // do something 
}); 

foo(); 
foo(); 
alert(foo.getCount()); 
Questions connexes