Подтвердить что ты не робот

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

Я хочу немного очистить свой проект, и теперь я пытаюсь использовать классы es6 для своих маршрутов. Моя проблема в том, что этот всегда undefined.

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);
4b9b3361

Ответ 1

попробуйте использовать код для вывода 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);

Ответ 2

Это происходит потому, что вы передали метод как отдельную функцию для выражения. 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 не так хороши, как могут показаться.

Ответ 3

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

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 в вашем файле Router.

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

Ответ 4

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

например:

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