Javascript 构建NodeJS模块-变量和方法

Javascript 构建NodeJS模块-变量和方法,javascript,node.js,closures,commonjs,Javascript,Node.js,Closures,Commonjs,我想创建模块来构造我的NodeJS应用程序,但是我有点迷路了,而且我还没有找到任何关于这个主题的完全确定的东西(经过数小时的搜索) 假设我想创建一个“用户”模块,通过该模块,我可以使用以下方法在代码中创建新用户: var newUser = new User(); var User = require('../lib/user'); User.prototype.login = function() { db.doDbStuff('get user data query', f

我想创建模块来构造我的NodeJS应用程序,但是我有点迷路了,而且我还没有找到任何关于这个主题的完全确定的东西(经过数小时的搜索)

假设我想创建一个“用户”模块,通过该模块,我可以使用以下方法在代码中创建新用户:

var newUser = new User();
var User = require('../lib/user');
User.prototype.login = function()    {
    db.doDbStuff('get user data query', function(_error, _result)    {
         this.username = _result[0].name; //this code will not work
    });
}
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.
    });
}
理想情况下,我会要求在代码顶部使用以下模块:

var newUser = new User();
var User = require('../lib/user');
User.prototype.login = function()    {
    db.doDbStuff('get user data query', function(_error, _result)    {
         this.username = _result[0].name; //this code will not work
    });
}
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.
    });
}
这很有效。问题是,我应该如何构造用户模块?以下是最好的方法吗

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;
    }
}
我正在为各种模块变量编写getter和setter,允许我隐藏我不想从其他代码意外访问的内容。但是,我以前也这样做过:

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库来编辑用户的属性,我就不能。这看起来像:

var newUser = new User();
var User = require('../lib/user');
User.prototype.login = function()    {
    db.doDbStuff('get user data query', function(_error, _result)    {
         this.username = _result[0].name; //this code will not work
    });
}
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.
    });
}
据我所知,代码不起作用,因为“this”关键字在闭包的范围内,而不是用户。即使代码要放在用户函数中:

function User() {
    this.login = function()    { //you know
这是行不通的

我想我的问题是,这个问题的最佳解决方案是什么?这是我在第一个代码块中介绍的方法吗?这看起来相当麻烦和混乱,而且容易发生冲突。我很害怕

提前谢谢

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'
我通常使用第二种方法,将函数附加到原型

变量“在闭包中不可用”的问题与原型无关。无论采用哪种方式,你都会遇到同样的问题

这与javascript经常混淆的动态
有关:

基本上,您需要做如下操作:

var newUser = new User();
var User = require('../lib/user');
User.prototype.login = function()    {
    db.doDbStuff('get user data query', function(_error, _result)    {
         this.username = _result[0].name; //this code will not work
    });
}
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:

在绑定函数中,
的值将是您提供给
的任何值。绑定(值)

无论您是使用
function.bind
还是
self=this
都是一个个人喜好的问题,但前几天我们在freenode中做了一些基准测试,发现
bind()
var self=this
慢20多倍


至于您最初提出的关于如何构造模块的问题,github上有很多示例可供学习。只需找到您最喜欢的模块并检查它们是如何构建的。我注意到许多人似乎更喜欢工厂而不是直接公开构造函数(例如,
require('module').create()
)。你的电话。

作为一种不同的方式,我喜欢以下模式

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); } }; }; module.exports=函数用户(数据){ //这完全是私事。 私有风险; var username=data.username; var pass=data.pass;//等 函数privateFunc(){ } 返回{ 登录:功能(cb){ db.doStuff(用户名、密码、cb); } }; };
如果这些都没有意义,我提前道歉,我只是吃了一些治智齿的止痛药,感觉有点轻,有点怪。似乎更多的是在javascript架构领域,而不是一般的node.js。值得注意的是,在你的两个例子中,变量都不是私有的。你应该看看:我想唐所指的页面已经移动到了哦。这是如此的聪明和简单!天哪谢谢当它发生意外变化时,它的动态特性确实令人困惑,但当你真正有意使用它时,它也是Javascript最强大的功能之一。是的,Javascript给了我一种非常奇怪的感觉,非常强大,令人敬畏,再加上“哦,我的天,这太荒谬了。”--有没有什么方法可以推荐使用prototype方法来保持某些成员的私有性?@Matt:您可以使用Python的方法:在其前面加下划线,并将其用作约定“这是私有的;除非您知道自己在做什么,否则不要碰它”。只要不将它们添加到导出/此对象中,它们将是私有的。您可以使用
bind()
调用当前对象上的方法。但是请注意,module.require将始终返回相同的对象,因此这些变量本质上是“静态的”。更难的问题是如何创建私有实例变量。我想大多数人都会选择更简单的“this.\u thisIsPrivate”方法(丑陋但有效),但你也可以这样做:我也喜欢这样。但这种方法只适用于单身人士,对吗?您不能以这种方式实例化。@owzim此模式实际上不仅适用于单例,它看起来非常类似于module.exports=(function(){…})();这是一个单一的模式,因为它直接执行函数。但是这个答案中的代码不是单例代码,因为您现在可以执行require('data')(my_instance_data);