Saya sudah mencoba mencari apa yang tampaknya menjadi seluruh internet, tetapi saya masih terganggu oleh masalah dengan kelas JS yang saya tulis untuk Layanan Mikro (masih dalam pembelajaran sedikit).

Jadi, saya mencoba memanggil metode kelas pada objek yang dipakai, dan menurut pengetahuan saya dan pengujian unit saya (saya kira) itu harus berfungsi.

Baiklah, saya akan mulai dengan kesalahan yang saya terima:

    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)

(Dan banyak lagi).

Kode panggilan kode:

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

Pemanggil pengontrol

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;
};

Saya benar-benar tidak tahu mengapa this tidak terdefinisi di UserController.

Bantuan apapun akan sangat dihargai.

21
KarlGdawg 11 Agustus 2017, 23:05

2 jawaban

Jawaban Terbaik

Saat Anda melakukan ini:

router.get('/users', userController.list);

Apa yang diteruskan ke router Anda hanyalah referensi ke metode .list. Instance userController hilang. Ini tidak unik untuk router - ini adalah properti umum tentang bagaimana hal-hal dilewatkan dalam Javascript. Untuk memahami lebih lanjut, apa yang pada dasarnya Anda lakukan adalah ini:

let list = userController.list; 
// at this point the list variable has no connection at all to userController
router.get('/users', list);

Dan, dalam mode strict Javascript, saat Anda memanggil fungsi biasa tanpa referensi objek apa pun seperti memanggil list() di atas, maka this akan menjadi undefined di dalam fungsi tersebut. Itulah yang terjadi dalam contoh Anda. Untuk memperbaikinya, Anda perlu memastikan bahwa metode Anda dipanggil dengan referensi objek yang tepat seperti pada userController.list(...) sehingga interpreter menetapkan nilai this dengan tepat.

Ada beberapa cara untuk memecahkan masalah ini:

Buat pembungkus fungsi Anda sendiri

router.get('/users', function(req, res)  {
    userController.list(req, res);
});

Ini berfungsi di semua versi Javascript.


Menggunakan .bind() untuk membuat pembungkus untuk Anda yang memanggilnya dengan objek yang tepat

router.get('/users', userController.list.bind(userController));

Ini berfungsi di ES5+ atau dengan polyfill .bind().


Gunakan pintasan fungsi panah ES6

router.get('/users', (...args) => userController.list(...args));

Ini berfungsi di ES6+


Secara pribadi, saya lebih suka implementasi .bind() karena saya pikir itu lebih sederhana dan lebih deklaratif/jelas daripada yang lain dan "pintasan" ES6 tidak terlalu pendek.

60
jfriend00 11 Agustus 2017, 21:04

router.get() tidak akan memanggil kelas Anda seperti yang Anda pikirkan. Anda memberinya referensi ke fungsi yang akan dipanggil dalam konteks makna router.get, itu tidak akan berada dalam konteks userController Anda.

Anda dapat memperbaikinya dengan melakukan:

router.get('/users', function(){userController.list(...arguments)});

Dengan kata lain, tidak memiliki referensi penggunaan ekspres userController ke list, memiliki penggunaan ekspres penutupan yang akan memiliki userController panggilan list dengan argumen yang diberikan.

3
zero298 11 Agustus 2017, 20:18