Подтвердить что ты не робот

Структурирование модуля NodeJS - переменные и методы

Я хочу создать модули для структурирования моего приложения 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;

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

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

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

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

Спасибо заранее!

4b9b3361

Ответ 1

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

Проблема, с которой вы сталкиваетесь с переменными, "недоступными в закрытии", не имеет ничего общего с прототипами. У вас будет такая же проблема, как вы ее структурируете.

Это связано с javascript oft-confusing dynamic 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()). Ваш звонок.

Ответ 2

В качестве другого подхода я являюсь поклонником следующего шаблона.

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

Ответ 3

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'.