Nodejs, экспресс-маршруты как классы es6

Я хочу немного очистить свой проект, и теперь я пытаюсь использовать классы 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);

4 ответов


попробуйте использовать код для pin this:

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

вы можете выйти из шаблона, используя подчеркивание bindAll. Например:

var _ = require('underscore');

// ..

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

Я также обнаружил, что es7 позволяет писать код более элегантно:

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

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

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

это происходит потому, что вы передали метод как автономную функцию для выражения. 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);
  • вам не придется беспокоиться о стоимости this
  • не имеет значения, вызывается ли функция с помощью new или
  • вы можете избежать сложности вызова bind на каждом маршруте

есть хороший список ресурсов здесь, о том, почему классы ES6 не так хороши, как может показаться.


приведенные выше ответы кажутся немного более сложными. Проверьте, что я сделал здесь:

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();
});

Я бы разделил два файла, так что вам просто потребуется Routes класса в .

надеюсь, что это помогло!


или, если вам не нравится связывать контекст на маршруты, вы можете привязать его к методам в самом конструкторе класса.

например:

constructor() {
   this.foo = 10;
   this.Root = this.Root.bind(this);
}