Nodejs,表达路由为es6类

时间:2015-11-19 08:44:22

标签: javascript node.js express this nodes

我想稍微清理一下我的项目,现在我尝试将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);

6 个答案:

答案 0 :(得分:13)

尝试使用代码固定app.get('/', routes.Root.bind(routes));

var _ = require('underscore');

// ..

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

您可以使用下划线bindAll功能退出样板。例如:

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

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

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

我还发现es7允许您以更优雅的方式编写代码:

Date.now = function () {
    return new Date().getTime();
}

var last_group = {
    me: false,
    time:Date.now()
}
var messages_count = 0;

function addMessage(msg, pseudo, date, me) {
    messages_count++;

    if(messages_count < 1){
        console.log('first message');
        createGroup(msg, pseudo, date, me);
        last_group.me = me;
    } else {

        if(last_group.me == me){
            if(last_group.time + 10000 > Date.now()) {
                 //console.log('adding to last group');                
                 addToGroup(msg, pseudo, date, me);                
            } else {                
                //console.log('creating new group', last_group.me, me);
                createGroup(msg, pseudo, date, me);
            }

        } else {

            //console.log('creating new group', last_group.me, me);
            createGroup(msg, pseudo, date, me);

        }   
    }
}

function addToGroup(msg, pseudo, date, me){
    $("#group-" + last_group.time).append('<div class="row message' + (me ? ' self' : '') + '">' + pseudo + '<p>' + msg + '</p></div>');
}

function createGroup(msg, pseudo, date, me){
    last_group.time = Date.now();
    var html = '<div class="group" id="group-' + last_group.time + '"><div class="row message' + (me ? ' self' : '') + '">' + pseudo + ' - ' + Date.now() + '<p>' + msg + '</p></div></div><br>';
    //console.log(html);
    $("#chatEntries").append(html);            
    last_group.me = me;
}

setInterval(function () {
    addMessage('Hello', 'pseudo', new Date().getTime(), true);
}, 1000);

setInterval(function () {
    addMessage('Hello 2', 'pseudo 2', new Date().getTime(), false);
}, 5000);

答案 1 :(得分:8)

这种情况正在发生,因为您已将方法作为独立函数传递来表达。 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的复杂性

有一个很好的资源列表here,关于为什么ES6课程看起来不那么好。

答案 2 :(得分:3)

或者如果你不喜欢绑定每个路由的上下文,你可以选择将它绑定到类的构造函数本身的方法。

E.g:

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

答案 3 :(得分: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();
});

我会将这两个文件分开,以便您只需要将Routes类放入Router文件中。

希望这有帮助!

答案 4 :(得分:2)

我们最近将所有Express控制器重构为使用基本控制器类,并且也遇到了此问题。我们的解决方案是通过从构造函数中调用以下辅助方法,使每个控制器将其方法绑定到自身:

  /**
   * Bind methods
   */
  bindMethods() {

    //Get methods
    const proto = Object.getPrototypeOf(this);
    const methods = [
      ...Object.getOwnPropertyNames(Controller.prototype),
      ...Object.getOwnPropertyNames(proto),
    ];

    //Bind methods
    for (const method of methods) {
      if (typeof this[method] === 'function') {
        this[method] = this[method].bind(this);
      }
    }
  }

这确保父控制器方法和子对象类中的任何自定义方法都正确绑定(例如Foo extends Controller)。

答案 5 :(得分:2)

import express from 'express';
const app = express();

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

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

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

这里是对代码的少量重写,但是正如这里的一些答案所指出的那样,在引用类似路由配置中的函数本身时,它并没有意识到this,必须对其进行绑定。为了解决这个问题,您不必编写“常规”功能,而只需编写定义“胖箭头”功能即可自动绑定自身,那么您就很好了!