Структурирование модуля 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
Это не сработает.
Я думаю, мой вопрос в том, какое лучшее решение этой проблемы? Это метод, который я представил в первом блоке кода? Это кажется довольно громоздким и беспорядочным и подверженным переменному столкновению. Я боюсь.
Спасибо заранее!
Ответы
Ответ 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'
.