web-dev-qa-db-ja.com

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;

これも機能しますが、注意点が1つあります。クロージャー内からユーザープロパティにアクセスする方法を見つけていません。 2番目の実装で私の理解が正しい場合、私はできません。つまり、ユーザーのプロパティを編集するためのコールバックとして関数を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

うまくいきません。

私の質問は、この問題の最良の解決策は何ですか?最初のコードブロックで示したメソッドですか?それはかなり面倒で面倒で、変数の衝突が発生しやすいようです。怖いです。

前もって感謝します!

26
Matt Egan

私は通常、プロトタイプに関数をアタッチする2番目のアプローチを使用します。

「クロージャで使用できない」変数に関する問題は、プロトタイプとは関係ありません。あなたはそれを構造化する方法のいずれかで同じ問題を抱えているでしょう。

これは、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())。あなたの電話。

25
timoxley

別のアプローチとして、私は次のパターンのファンです。

 module.exports = function User(data){
 
 //この適切にプライベートなもの。
 
 var privateVar; 
 var username = data.username; 
 var pass = data.pass; //etc

 function privateFunc(){
} 
 
 return {
 login:function(cb){
 db.doStuff(username、pass、cb); 
} 
}; 
}; 
12
Maleck13
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'

2
Alon Valadji