2015-11-19 10 views
12

私のプロジェクトをちょっときれいにしたいので、私のルートにes6クラスを使用しようとしています。私の問題は、です。は常に未定義です。Nodejs、es6クラスとしてのルートを表現

var express = require('express'); 
var app = express(); 

class Routes { 
    constructor(){ 
     this.foo = 10 
    } 

    Root(req, res, next){ 
     res.json({foo: this.foo}); // TypeError: Cannot read property 'foo' of undefined 
    } 
} 

var routes = new Routes(); 
app.get('/', routes.Root); 
app.listen(8080); 

答えて

10

thisを固定するためのコードを使用しよう:

app.get('/', routes.Root.bind(routes)); 

あなたはbindAll機能を強調使用して定型から抜け出すことができます。たとえば:

class Routes { 
    constructor(){ 
     this.foo = 10 
    } 

    Root = (req, res, next) => { 
     res.json({foo: this.foo}); 
    } 
} 

var routes = new Routes(); 
app.get('/', routes.Root); 
+1

ES7がここに到達するまで - 私はそれを完全に知らなかった_.bindAll大好きです。すべてのルートでユーザーを自分自身にバインドするよりもはるかに良いです! –

5

これが起こっているあなたが表現するために、スタンドアロン関数としてメソッドに渡さたので:

var _ = require('underscore'); 

// .. 

var routes = new Routes(); 
_.bindAll(routes) 
app.get('/', routes.Root); 

私はまた、ES7は、よりエレガントな方法でコードを記述することができますことを発見しました。 Expressはそれが由来するクラスについて何も知らないため、メソッドが呼び出されるときにはどの値をthisとして使用するか分かりません。

thisの値をbindにすることができます。

app.get('/', routes.Root.bind(routes)); 

また、ルートを管理するための代替構成を使用することもできます。クラスなしでオブジェクト指向プログラミングに構文上の利点をたくさん使用することができます。

function Routes() { 
    const foo = 10; 

    return { 
    Root(req, res, next) { 
     res.json({ foo }); 
    } 
    }; 
} 

const routes = Routes(); 
app.get('/', routes.Root); 
app.listen(8080); 
  • あなたは機能は、あなたが上bindを呼び出すのでは煩雑さを避けることができるnew
  • と呼ばれているかどうかは関係ありませんthis
  • の値を心配する必要はありません各ルート

リソース一覧はhereですが、なぜES6クラスがそれほど良くないのかについては、こちらをご覧ください。

2

上記の回答はちょっと複雑すぎるようです。私はここで何をやったかチェックアウト:それはこのクラスを使用することになると

class Routes { 
    constructor(req, res, next) { 
    this.req = req; 
    this.res = res; 
    this.next = next; 
    this.foo = "BAR" 
    // Add more data to this. here if you like 
    } 

    findAll(){ 
    const {data, res,} = this; // Or just reference the objects directly with 'this' 
    // Call functions, do whaterver here... 
    // Once you have the right data you can use the res obejct to pass it back down 

    res.json ({foo: this.foo}); // Grabs the foo value from the constructor 

    } 
} 

は今、あなたはこの線に沿って何かを行うことができます、

var express = require('express'); 
var router = express.Router(); 
var {Routes} = require('./Routes'); 

router.get('/foo', (req, res, next) => { 
    new Routes(req, res, next).findAll(); 
}); 

が、私は2つのファイルを区切るなるようにしますRouterファイルにRoutesクラスが必要です。

これが役に立った!

+0

これは受け入れられた答えよりもはるかに複雑に思えます。これには、req、res、next()のクラスのprivateメンバーが必要です。これらのクラス・メンバーは、実際には、必要なExpressミドルウェア・タイプと同じシグネチャーを提供するだけのミドルウェア機能です。 '.bind'メソッドを使うことは、この設計上の配慮にとって最善の解決策です。メモとして、私はこれをTypeScriptでやっていて、うまく動いているようです。 –

1

または、ルートごとにコンテキストをバインドしたくない場合は、オプションで、クラスのコンストラクタ自体のメソッドにバインドできます。

例えば:

constructor() { 
    this.foo = 10; 
    this.Root = this.Root.bind(this); 
} 
関連する問題