为什么 "this" 在此 class 方法中未定义?
Why is "this" undefined in this class method?
我试图搜索整个互联网,但我仍然为 JS 的问题而烦恼 class我正在为微服务写作(仍在学习位)。
因此,我尝试在实例化对象上调用 class 方法,根据我的知识和我的(我认为是错误的)单元测试,它应该可以工作。
好吧,我将从我收到的错误开始:
GET /api/users 500 2.863 ms - 2649
TypeError: Cannot read property 'repository' of undefined
at list (C:\Users\<user>\Documents\Programming\node\kaguwa-ngn\kaguwa-user-service\controllers\user-controller.js:20:9)
at Layer.handle [as handle_request] (C:\Users\<user>\Documents\Programming\node\kaguwa-ngn\kaguwa-user-service\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\<user>\Documents\Programming\node\kaguwa-ngn\kaguwa-user-service\node_modules\express\lib\router\route.js:137:13)
(还有更多)。
代码调用代码:
user-controller.js
'use strict';
var utils = require('./utils');
class UserController {
constructor(repository) {
this.repository = repository || {};
}
/**
*
* Lists all users.
*
* @param {object} req
* @param {object} res
*/
list(req, res) {
this.repository.list(function (err, users) {
if (err) return res.status(500).json(utils.createError(500));
if (Object.keys(users).length !== 0) {
res.json(users);
} else {
res.status(404).json(utils.createNotFound('user', true));
}
});
}
// more code
}
module.exports = UserController
控制器的调用者
user-api.js
'use strict';
var express = require('express');
var UserController = require('../controllers/user-controller');
var router = express.Router();
module.exports = function (options) {
var userController = new UserController(options.repository);
router.get('/users', userController.list);
// Mode code
return router;
};
我真的不知道为什么 this
在 UserController
中未定义。
如有任何帮助,我们将不胜感激。
router.get()
不会像您认为的那样调用您的 class。你给它一个函数的引用,它将在 router.get
的上下文中调用,意思是,它不会在你的 userController 的上下文中。
您可以通过以下方式解决此问题:
router.get('/users', function(){userController.list(...arguments)});
换句话说,没有明确使用 userController
对 list
的引用,有明确使用将 userController
调用 list
的闭包给定的参数。
当你这样做时:
router.get('/users', userController.list);
传递给路由器的只是对 .list
方法的引用。 userController 实例丢失。这不是路由器独有的——这是一个通用的 属性 事物如何在 Javascript 中传递。要进一步了解,您实际上在做的是:
let list = userController.list;
// at this point the list variable has no connection at all to userController
router.get('/users', list);
而且,在Javascript的strict
模式下,当你调用一个没有任何对象引用的常规函数时,比如上面调用list()
,那么this
将是undefined
函数内部。这就是您的示例中发生的情况。要修复它,您需要确保使用正确的对象引用调用您的方法,如 userController.list(...)
中那样,以便解释器适当地设置 this
值。
有多种方法可以解决这个问题:
制作您自己的函数包装器
router.get('/users', function(req, res) {
userController.list(req, res);
});
这适用于 Javascript 的任何版本。
使用 .bind()
为您制作包装器,用正确的对象调用它
router.get('/users', userController.list.bind(userController));
这适用于 ES5+ 或 .bind()
polyfill。
使用 ES6 箭头函数快捷方式
router.get('/users', (...args) => userController.list(...args));
这适用于 ES6+
就我个人而言,我更喜欢 .bind()
实现,因为我认为它比其他任何实现都更简单 declarative/clearer,而且 ES6 "shortcut" 并不是真的更短。
我试图搜索整个互联网,但我仍然为 JS 的问题而烦恼 class我正在为微服务写作(仍在学习位)。
因此,我尝试在实例化对象上调用 class 方法,根据我的知识和我的(我认为是错误的)单元测试,它应该可以工作。
好吧,我将从我收到的错误开始:
GET /api/users 500 2.863 ms - 2649
TypeError: Cannot read property 'repository' of undefined
at list (C:\Users\<user>\Documents\Programming\node\kaguwa-ngn\kaguwa-user-service\controllers\user-controller.js:20:9)
at Layer.handle [as handle_request] (C:\Users\<user>\Documents\Programming\node\kaguwa-ngn\kaguwa-user-service\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\<user>\Documents\Programming\node\kaguwa-ngn\kaguwa-user-service\node_modules\express\lib\router\route.js:137:13)
(还有更多)。
代码调用代码:
user-controller.js
'use strict';
var utils = require('./utils');
class UserController {
constructor(repository) {
this.repository = repository || {};
}
/**
*
* Lists all users.
*
* @param {object} req
* @param {object} res
*/
list(req, res) {
this.repository.list(function (err, users) {
if (err) return res.status(500).json(utils.createError(500));
if (Object.keys(users).length !== 0) {
res.json(users);
} else {
res.status(404).json(utils.createNotFound('user', true));
}
});
}
// more code
}
module.exports = UserController
控制器的调用者
user-api.js
'use strict';
var express = require('express');
var UserController = require('../controllers/user-controller');
var router = express.Router();
module.exports = function (options) {
var userController = new UserController(options.repository);
router.get('/users', userController.list);
// Mode code
return router;
};
我真的不知道为什么 this
在 UserController
中未定义。
如有任何帮助,我们将不胜感激。
router.get()
不会像您认为的那样调用您的 class。你给它一个函数的引用,它将在 router.get
的上下文中调用,意思是,它不会在你的 userController 的上下文中。
您可以通过以下方式解决此问题:
router.get('/users', function(){userController.list(...arguments)});
换句话说,没有明确使用 userController
对 list
的引用,有明确使用将 userController
调用 list
的闭包给定的参数。
当你这样做时:
router.get('/users', userController.list);
传递给路由器的只是对 .list
方法的引用。 userController 实例丢失。这不是路由器独有的——这是一个通用的 属性 事物如何在 Javascript 中传递。要进一步了解,您实际上在做的是:
let list = userController.list;
// at this point the list variable has no connection at all to userController
router.get('/users', list);
而且,在Javascript的strict
模式下,当你调用一个没有任何对象引用的常规函数时,比如上面调用list()
,那么this
将是undefined
函数内部。这就是您的示例中发生的情况。要修复它,您需要确保使用正确的对象引用调用您的方法,如 userController.list(...)
中那样,以便解释器适当地设置 this
值。
有多种方法可以解决这个问题:
制作您自己的函数包装器
router.get('/users', function(req, res) {
userController.list(req, res);
});
这适用于 Javascript 的任何版本。
使用 .bind()
为您制作包装器,用正确的对象调用它
router.get('/users', userController.list.bind(userController));
这适用于 ES5+ 或 .bind()
polyfill。
使用 ES6 箭头函数快捷方式
router.get('/users', (...args) => userController.list(...args));
这适用于 ES6+
就我个人而言,我更喜欢 .bind()
实现,因为我认为它比其他任何实现都更简单 declarative/clearer,而且 ES6 "shortcut" 并不是真的更短。