`this`在expressJS路由处理程序中未定义

时间:2016-01-08 15:26:34

标签: javascript node.js express

groups.js

class groupsCtrl {
  constructor() {
    this.info = "test";
  }

  get(res, req) {
    console.log("LOG ! ", JSON.stringify(this));
  }
}
module.exports = new groupsCtrl(); //singleton

routes.js

var express = require('express');
var router = express.Router();

var groupsCtrl = require('controllers/api_admin/groups.js');
router.get('/groups/', groupsCtrl.get);

记录LOG ! undefined

如何在控制器类中访问this

4 个答案:

答案 0 :(得分:18)

您需要将方法绑定到实例。

一个解决方案:

update

另一种解决方案:

router.get('/groups/', groupsCtrl.get.bind(groupsCtrl));

或者使用es6bindall之类的东西(基本上和上面的代码一样,但是当你需要绑定多个方法时可能会更有用)。

答案 1 :(得分:1)

2020更新

  • 虽然@robertkiep发布的两种解决方案都无法胜任,但我想强调的是,这两种解决方案看起来都很丑陋且无法维护
  • 当有大量路由时,执行router.get('/ groups /',groupsCtrl.get.bind(groupsCtrl))的方法1看起来真的很丑
  • 当控制器的路由很多时,方法2变得很麻烦
  • 由于您的示例只有一条路线,所以我来说明问题

使用方法2

class AuthController {
  constructor({ db, pgp, logger }) {
    super({ db, pgp, logger })
    this.postLogin = this.postLogin.bind(this)
    this.postLogout = this.postLogout.bind(this)
    this.postSignup = this.postSignup.bind(this)
    this.postForgot = this.postForgot.bind(this)
    this.getReset = this.getReset.bind(this)
    this.postReset = this.postReset.bind(this)
  }

  postLogin(req, res, next) {
    
  }

  postLogout(req, res, next) {

  }

  async postSignup(req, res, next) {
    
  }

  async postForgot(req, res, next) {
    
  }

  async getReset(req, res, next) {
    
  }

  async postReset(req, res, next) {
    
  }
}

每次添加新方法时,构造函数都需要进一步更新

方法3

我认为这更清洁,不需要维护,您可以根据需要继续添加方法

  • 想法是使用Object.hasOwnPropertyName获取所有方法名称的数组,然后以编程方式将其绑定
  • 例如,如果您编写Object.hasOwnPropertyName(AuthController.prototype),它将为您提供数组中的所有非静态方法
  • 在上面的示例中,您将获得['constructor','postLogin','postLogout'...]
  • 如果调用Object.hasOwnPropertyName(AuthController),则会获得STATIC方法
  • 让我们以编程方式调用它们

除了牢记静态和非静态方法外,该控制器几乎不需要维护,只需过滤掉构造函数即可删除构造函数,然后在每个实例上调用bind

class AuthController {
  constructor({ db, pgp, logger }) {
    super({ db, pgp, logger })
    this.postLogin = this.postLogin.bind(this)
    this.postLogout = this.postLogout.bind(this)
    this.postSignup = this.postSignup.bind(this)
    this.postForgot = this.postForgot.bind(this)
    this.getReset = this.getReset.bind(this)
    this.postReset = this.postReset.bind(this)

    Object.getOwnPropertyNames(AuthController.prototype)
      .filter((propertyName) => propertyName !== 'constructor')
      .forEach((method) => (this[method] = this[method].bind(this)))
  }

  postLogin(req, res, next) {
    
  }

  postLogout(req, res, next) {

  }

  async postSignup(req, res, next) {
    
  }

  async postForgot(req, res, next) {
    
  }

  async getReset(req, res, next) {
    
  }

  async postReset(req, res, next) {
    
  }
}

答案 2 :(得分:0)

上面的答案很好,我想补充一点以澄清:

假设我们有一堂课:

class TClass {
  constructor(arg) {
    this.arg = arg
  }
  test() {
    console.log(this.arg)
  }
}

这将不起作用:

const t = new TClass("test")
const method = t.test  // method is simply a reference without context
method() // 'this' is not defined

这将起作用:

const t = new TClass("test")
t.test() // log 'test'

原因与上面的注释类似,对该函数的引用没有上下文

答案 3 :(得分:0)

class groupsCtrl {
    constructor() {
        this.info = 'test';
    }

    get = (res, req) => {
        console.log('LOG ! ', JSON.stringify(this));
    };
}

您可以只使用箭头功能来避免样板代码