私はインターネット全体のように見えるものを検索しようとしましたが、まだマイクロサービス用に作成しているJSクラスの問題にまだ悩まされています(まだ少し学習中です)。
したがって、インスタンス化されたオブジェクトでクラスメソッドを呼び出そうとします。私の知識と私の(誤ったと思います)ユニットテストによると、それは機能するはずです。
まあ、私が受け取るエラーから始めましょう:
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('/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
になります関数。それがあなたの例で起こっていることです。これを修正するには、インタプリタがthis
値を適切に設定できるように、userController.list(...)
のように適切なオブジェクト参照を使用してメソッドが呼び出されるようにする必要があります。
この問題を解決するには、いくつかの方法があります。
独自の関数ラッパーを作成する
_router.get('/users', function(req, res) {
userController.list(req, res);
});
_
これは、Javascriptのどのバージョンでも機能します。
.bind()
を使用して、適切なオブジェクトで呼び出すラッパーを作成します
_router.get('/users', userController.list.bind(userController));
_
これはES5 +または.bind()
ポリフィルで機能します。
ES6矢印関数のショートカットを使用
_router.get('/users', (...args) => userController.list(...args));
_
これはES6以降で機能します
個人的には、.bind()
実装が他のどれよりも単純で宣言的/明確であり、ES6の「ショートカット」が実際には短くないため、私はそれを好みます。
router.get()
は、あなたが思っているようにクラスを呼び出しません。 router.get
の意味で呼び出す関数への参照を与えていますが、userControllerのコンテキストではありません。
これを修正するには、次のようにします。
router.get('/users', function(){userController.list(...arguments)});
言い換えると、userController
へのlist
の参照を明示的に使用せず、指定された引数でuserController
を呼び出すlist
を使用するクロージャを明示的に使用する。