构建NodeJS模块 - 变量和方法

时间:2012-02-14 00:23:22

标签: javascript node.js closures commonjs

我想创建模块来构建我的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;
    }
}

我正在为各种模块变量编写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库作为回调来编辑用户的属性,我不能。这看起来像是:

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

根据我的理解,代码不起作用,因为“this”关键字在闭包范围内,而不是User。即使代码放在用户函数中:

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

它不会起作用。

我想我的问题是,这个问题的最佳解决方案是什么?这是我在第一个代码块中提出的方法吗?这似乎相当麻烦和混乱,容易发生变量冲突。我很害怕。

提前致谢!

3 个答案:

答案 0 :(得分:25)

我通常采用第二种方法,将功能附加到原型上。

您对变量“无法在闭包中使用”所遇到的问题与原型无关。无论你如何构建它,你都会遇到同样的问题。

这与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())。你的电话。

答案 1 :(得分:12)

作为一种不同的方法,我是以下模式的粉丝。

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 :(得分:2)

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'