Структурирование модуля NodeJS - переменные и методы - PullRequest
26 голосов
/ 14 февраля 2012

Я хочу создать модули для структурирования моего приложения NodeJS, но я немного растерялся, и я не нашел ничего (с часами поиска), которое было бы полностью определенным по этому вопросу.

Скажем, я хотел бы создать «пользовательский» модуль, из которого я могу создавать новых пользователей в своем коде, используя что-то вроде:

var newUser = new User();

В идеале, мне потребуется мой модульв верхней части моего кода, используя что-то вроде:

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

Это прекрасно работает.Вопрос в том, как мне структурировать пользовательский модуль?Является ли следующий способ наилучшим?

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;
    }
}

Я пишу методы получения и установки для переменных моего модуля, что позволяет мне скрывать вещи, к которым я не хочу, случайно обращаться из другого кода.Тем не менее, я делал это раньше:

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;

Это тоже работает, с одной оговоркой;Я не нашел способ доступа к свойствам пользователя из замыканий.Если мое понимание верно, со второй реализацией я не могу.Это означает, что если мне нужно передать функцию в библиотеку БД в качестве обратного вызова для редактирования свойств пользователя, я не смогу.Это выглядело бы примерно так:

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

Насколько я понимаю, код не работает, потому что ключевое слово "this" находится в области действия замыкания, а не пользователя.Даже если бы код был помещен в пользовательскую функцию:

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

Это не сработало бы.

Я думаю, мой вопрос, каково лучшее решение этой проблемы?Это метод, который я представил в первом блоке кода?Это кажется довольно громоздким, грязным и подверженным переменным столкновениям.Я напуган.

Заранее спасибо!

Ответы [ 3 ]

25 голосов
/ 14 февраля 2012

Я обычно использую второй подход, прикрепляя функции к прототипам.

Проблема с переменными «недоступность в замыканиях» не имеет ничего общего с прототипами. У вас будет та же проблема в любом случае.

Это связано с часто сбивающей с толку динамикой javascript this: http://robotlolita.me/2011/10/09/understanding-javascript-oop.html#sec-2-1

По сути, вам нужно сделать что-то вроде:

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.
    });
}

У вас также есть возможность использовать function.bind: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

В пределах связанной функции значение this будет любым значением, которое вы указали для .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));
}

Используете ли вы function.bind или self = this - это вопрос личного вкуса, но на днях мы выполняли некоторые тесты в freenode # nodejs и обнаружили, что bind() в 20 раз медленнее, чем var self = this.

Что касается вашего первоначального вопроса о том, как структурировать модули, на github есть много примеров для изучения. Просто найдите ваш любимый модуль и проверьте, как они его структурируют. Я заметил, что многие люди предпочитают фабрики, а не выставляют конструкторов напрямую (например, require('module').create()). Ваш звонок.

12 голосов
/ 26 января 2013

Как другой подход, я фанат следующей схемы.

module.exports = function User(data) {

    //this properly private stuff.

    var privateVar;
    var username = data.username;
    var pass = data.pass; //etc

    function privateFunc() {
    }

    return {
        login: function(cb) {
            db.doStuff(username, pass, cb);
        }
    };
};
2 голосов
/ 14 февраля 2012
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
    });
}

'this', который вы использовали, находился вне области видимости, это был обратный вызов 'this'.

...