2010-02-07 7 views
1

J'ai une instance d'une classe de journalisation "logger", cette classe a une fonction "log (txt)", qui fonctionne.Javascript Objet/Fonction Question

Maintenant je déclare une classe différente "Runner" et je lui passe l'instance de logger dans le constructeur. Tout fonctionne jusqu'à ce que la ligne 5, mais la ligne 7 ne pas écrire dans le journal:

var Runner = function (logger) { 
    // constructor: 
    logger.log("this way it works"); 
    this.logger = logger; //line 4 
    this.logger.log("this also works"); //line 5 
    this.logf = this.logger.log; //create a shorthand for logging 
    this.logf("this is not written to log. why? i thought i can create a var for a function"); //line 7 
}; 

var logger = new Logger(); //class not shown here 
var runner = new Runner(logger); 
var otherinstancce = new OtherClass(logger) //line 12 

Pouvez-vous expliquer ce qui est mon erreur?

Répondre

4

contrairement à d'autres langues «ce » dans javascript est dynamique, c'est-à-dire que "this" est le contexte dans lequel la fonction a été appelée, et non où elle a été définie. Pour créer un couplage entre la fonction et son contexte, vous devez "verrouiller" le contexte dans une fermeture. La plupart des cadres fournissent un sucre pour cette sous forme de méthode bind(), qui, sous forme simplifiée, ressemble à ceci

Function.prototype.bind = function(o) { 
    var p = this; 
    return function() { p.apply(o) } 
} 

avec affectation de fonction contexte verrouillé fonctionne comme prévu

bar = foo.func.bind(foo) 
bar() // yes! 
+0

'function.bind' n'est pas seulement une fonctionnalité de framework, c'est une méthode standard de la prochaine version de JavaScript, ECMA262-5. En tant que tel, vous ne devez pas le pirater dans le prototype de la fonction sans vérifier qu'il n'est pas déjà là, et toute méthode que vous y mettez devrait prendre en charge toutes les fonctionnalités de la méthode 'bind' standard. Celui-ci ne gère pas les arguments-passes. Voir par exemple. le bas de http://stackoverflow.com/questions/1558065/access-event-object-in-event-handler/1558289#1558289 pour une implémentation complète. – bobince

1

Je pense que le problème peut être this.logf s'exécute dans la portée de l'objet runner par opposition à l'enregistreur. Si votre fonction logger.log utilise "this", elle utilisera le runner au lieu du logger.

7

Lorsque vous attribuez la fonction log au membre logf de l'objet actuel, il devient une fonction membre de cet objet actuel. Lorsque vous appelez est, l'objet this à l'intérieur de la fonction fera référence à son nouvel objet, pas à this.logger plus. Par conséquent, la fonction ne trouvera pas de variables autres fonctions qu'elle veut appeler sur l'objet de l'enregistreur.

Pour éviter cela, vous pouvez écrire une fonction simple qui transmet à l'objet enregistreur:

this.log = function() { return this.logger.log(arguments); } 

Ou, en utilisant une fermeture:

var obj = this.logger; 
this.log = function() { return obj.log(arguments); } 
+0

Après avoir lu votre réponse plusieurs fois je crois que je comprends. Une autre question se pose: pourrait-il y avoir du mal dans ce que je fais à la ligne 4? Est-ce que l'objet de l'enregistreur (que je transmettrai aussi aux instances d'autres classes, voir la ligne 12) sera-t-il endommagé ou modifié? – user89021

+1

@ user89021: Le 'this.logger' se référera simplement à l'objet' logger' d'origine et cela ne sera en aucun cas "blessé". Alors que les méthodes doivent savoir à quel objet elles appartiennent, les objets ne se soucient pas s'ils sont contenus par un autre objet. – sth