web-dev-qa-db-fra.com

Structurer un module NodeJS - variables et méthodes

Je veux créer des modules pour structurer mon application NodeJS, mais je suis un peu perdu et je n'ai rien trouvé (avec des heures de recherche) qui soit complètement définitif sur le sujet.

Disons que je voudrais créer un module "utilisateur", à partir duquel je peux créer de nouveaux utilisateurs dans mon code en utilisant quelque chose comme:

var newUser = new User();

Idéalement, j'aurais besoin de mon module en haut de mon code en utilisant quelque chose comme:

var User = require('../lib/user');

Cela fonctionne très bien. La question est, comment dois-je structurer le module utilisateur? Est-ce que la meilleure façon est la suivante?

module.exports = function User()    {
    var authorized = false;
    var username = undefined;
    var password = undefined;
    var statistics = undefined;

    this.authorized = function()  {
        return authorized;
    }
    this.username = function()  {
        return username;
    }
    this.statistics = function()    {
        return statistics;
    }
}

J'écris des getters et des setters pour mes différentes variables de module, ce qui me permet de cacher des choses auxquelles je ne veux pas accéder accidentellement à partir d'un autre code. Cependant, je l'ai fait de cette façon auparavant:

function User() {
    this.authStatus = false;
    this.email;
    this.displayName;
    this.inSession;
}

User.prototype.isAuthenticated = function() {
    return(this.authStatus && this.email && this.displayName)
}

User.prototype.isInSession = function() {
    return(this.inSession && this.isAuthenticated());
}

exports.User = User;

Cela fonctionne aussi, avec une mise en garde; Je n'ai pas trouvé de moyen d'accéder aux propriétés des utilisateurs depuis les fermetures. Si ma compréhension est correcte, avec la deuxième implémentation, je ne peux pas. Cela signifie que si je dois remettre une fonction à une bibliothèque db comme rappel pour modifier les propriétés de l'utilisateur, je ne peux pas. Cela ressemblerait à quelque chose comme:

User.prototype.login = function()    {
    db.doDbStuff('get user data query', function(_error, _result)    {
         this.username = _result[0].name; //this code will not work
    });
}

Le code ne fonctionne pas, à ma connaissance, car le mot-clé "this" est dans le cadre de la fermeture, pas l'utilisateur. Même si le code devait être placé dans la fonction utilisateur:

function User() {
    this.login = function()    { //you know

Ça ne marcherait pas.

Je suppose que ma question est, quelle est la meilleure solution à ce problème? Est-ce la méthode que j'ai présentée dans le premier bloc de code? Cela semble plutôt lourd et désordonné et sujet à des collisions variables. J'ai peur.

Merci d'avance!

27
Matt Egan

Je vais généralement avec la deuxième approche, en attachant des fonctions aux prototypes.

Le problème que vous rencontrez avec les variables "non disponibles dans les fermetures" n'a rien à voir avec les prototypes. Vous auriez le même problème de toute façon vous le structurez.

C'est à voir avec la dynamique souvent déroutante de javascript this: http://robotlolita.me/2011/10/09/understanding-javascript-oop.html#sec-2-1

Fondamentalement, vous devez faire quelque chose comme:

User.prototype.login = function()    {
    var self = this // bind this to self so you have a reference to what `this` was

    db.doDbStuff('get user data query', function(_error, _result)    {
         self.username = _result[0].name; // self refers to the original `this`, so this works.
    });
}

Vous avez également la possibilité d'utiliser function.bind: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

Dans la fonction liée, la valeur de this sera la valeur que vous avez fournie à .bind(value):

User.prototype.login = function()    {
    db.doDbStuff('get user data query', (function(_error, _result)    { 
         this.username = _result[0].name; // bind fixes the original `this`, so this also works.
    }).bind(this));
}

Que vous utilisiez function.bind Ou self = this Est en quelque sorte une question de goût personnel, mais nous faisions quelques benchmarks dans le freenode # nodejs l'autre jour et avons découvert que bind() est 20 quelque chose fois plus lent que var self = this.

Quant à votre question initiale sur la façon de structurer les modules, il y a tellement d'exemples à apprendre sur github. Trouvez simplement votre module préféré et inspectez la façon dont il le structure. Je remarque que beaucoup de gens semblent préférer les usines plutôt que d'exposer directement les constructeurs (par exemple require('module').create()). Ton appel.

25
timoxley

Comme approche différente, je suis fan du schéma suivant.

 module.exports = fonction Utilisateur (données) {
 
 // ce truc correctement privé. 
 
 var privateVar; 
 var username = data.username; 
 var pass = data.pass; //etc.............., fonction privateFunc () {
} 
 
 return {[...... ____.] db.doStuff (nom d'utilisateur, pass, cb); 
} 
}; 
}; 
12
Maleck13
User.prototype.login = function()    {
    var _this = this;
    db.doDbStuff('get user data query', function(_error, _result)    {
        _this.username = _result[0].name; //this code will now work
    });
}

Le 'this' vous avez utilisé était hors de sa portée, c'était le rappel 'this'.

2
Alon Valadji