构建NodeJS模块 - 变量和方法

Mat*_*gan 27 javascript closures commonjs node.js

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

假设我想创建一个"用户"模块,我可以使用以下内容在我的代码中创建新用户:

var newUser = new User();
Run Code Online (Sandbox Code Playgroud)

理想情况下,我需要使用以下代码之类的代码顶部的模块:

var User = require('../lib/user');
Run Code Online (Sandbox Code Playgroud)

这非常有效.问题是,我应该如何构建用户模块?以下是最好的方法吗?

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在为各种模块变量编写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;
Run Code Online (Sandbox Code Playgroud)

这也有效,但有一点需要注意; 我还没有找到一种从闭包内访问用户属性的方法.如果我的理解是正确的,那么第二个实现,我不能.这意味着如果我需要将一个函数关闭到db库作为回调来编辑用户的属性,我不能.这看起来像:

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

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

function User() {
    this.login = function()    { //you know
Run Code Online (Sandbox Code Playgroud)

它不会起作用.

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

提前致谢!

tim*_*ley 26

我通常采用第二种方法,将函数附加到原型.

你所拥有的变量"无法在闭包中使用"的问题与原型无关.无论你如何构建它,你都会遇到同样的问题.

它与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.
    });
}
Run Code Online (Sandbox Code Playgroud)

您还可以选择使用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));
}
Run Code Online (Sandbox Code Playgroud)

无论你是使用function.bind还是self = this某种个人品味问题,但是前几天我们在freenode#nodejs做了一些基准测试,发现bind()比它慢了20倍var self = this.

至于你关于如何构建模块的原始问题,有很多例子可以在github上学习.只需找到您喜欢的模块并检查它们的结构.我注意到许多人似乎更喜欢工厂而不是直接暴露构造函数(例如require('module').create()).你的来电.

  • 只是不要将它们添加到exports/this对象中,它们将是私有的.您可以使用`bind()`来调用当前对象上的方法.但请注意,module.require将始终返回相同的对象,因此这些变量基本上是"静态的".更难的问题是如何创建私有实例变量.我想大多数人选择更简单的'this._thisIsPrivate'方法(丑陋但有效),但你也可以这样做:http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-private - 变量式的JavaScript / (3认同)

Mal*_*k13 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);
        }
    };
};

  • 我也喜欢这个.但这种方法只适用于单身人士,对吧?你无法以这种方式实例化. (4认同)
  • @owzim这种模式实际上不仅适用于单例,它看起来非常类似于module.exports =(function(){...})(); 这是一个单一的模式,因为它直接执行功能.但是这个答案中的代码不是单例,因为你现在可以做require('data')(my_instance_data).myInstanceFunction(); (2认同)