Express JS在使用app.get(...)路由后,'this'变量未定义

15

我有一个基本的Node.js服务器,旨在用作API,我创建了一个日志和数据库模块,并开始添加其他模块来处理不同类型的请求。

我正在使用Express.js和node-mysql

当我访问/v1/group时,出现以下错误 -

TypeError: Cannot read property 'database' of undefined
    at Group.getAll (C:\code\javascript\node\api\api\v1\groups.js:12:23)
    at callbacks (C:\code\javascript\node\api\node_modules\express\lib\router\index.js:161:37) ...

所以我猜在收到请求并调用group.getAll()后,this是未定义的,但我不明白为什么,有没有一种方法可以设置this,或者我的应用程序结构是否有问题?

sever.js

"use strict";

var Express = require('express');
var Log = require('./database/log');
var Database = require('./database/database');
var dbConfig = require('./dbconfig.json');

var Group = require('./api/v1/groups');


//Init express
var app = new Express();

//Init log and database
var log = new Log();
var database = new Database(dbConfig, log);

var initCallback = function() {
    //Init routes
    var group = new Group(database, log);

    //Group routes
    app.get('/v1/group', group.getAll);
    app.get('/v1/group/:id', group.getByID);

    app.listen(3000);
    log.logMessage("INFO", "Listening on port 3000");
};

//Test database connection
database.getConnection(function(err, connection) {
    if (err) {
        log.logMessage("FATAL", "Error connecting to database, check database is running and the dbconfig.json file is present and correct.");
        process.exit(1);
    }
    connection.end();

    initCallback();
});

数据库.js

"use strict";

var mysql = require('mysql');


var Database = function(dbConfig, log) {
    this.connected = false;
    this.log = log;

    this.log.logMessage("INFO", "Connecting to database with: Host - " + dbConfig.dbhost + ", Database port - " + dbConfig.dbport + ", Database name - " + dbConfig.dbname + ", User " + dbConfig.dbuser + ", Password length - " + dbConfig.dbpass.length);

    this.pool  = mysql.createPool({
        host : dbConfig.dbhost,
        user : dbConfig.dbuser,
        port: dbConfig.dbport,
        password : dbConfig.dbpass,
        database: dbConfig.dbname
    });
};

Database.prototype.getConnection = function() {
    var args = arguments;
    return this.pool.getConnection.apply(this.pool, arguments);
};

module.exports = Database;

groups.js

"use strict";

var Group = function(database, log) {
    this.database = database;
    this.log = log;
};

Group.prototype.getAll = function(req, res) {
    console.log(this); // --> undefined

    var query = 'SELECT * FROM invgroups WHERE published = 1';

    this.database.getConnection(function(err, connection) { // --> error line
        if (err) { res.send(500, "Database error"); }

        connection.query(query, function(err, results) {
            if (err) { res.send(500, "Database error"); }
            res.send(results);
        });

        connection.end();
    });

};


Group.prototype.getByID = function(req, res) {
    console.log(this);
    res.send({name: "Group Item 1"});
};

module.exports = Group;
1个回答

34

你需要正确地绑定函数。

app.get('/v1/group', group.getAll);

只将getAll函数作为处理程序传递,但函数本身没有关于this的概念。 this是根据绑定的上下文或函数调用方式决定的。 这篇博客文章对理解函数上下文的工作原理非常有用。

app.get('/v1/group', group.getAll.bind(group));

工作得非常完美,非常感谢。我现在的结构方式正确吗?还是应该采用其他方式? - Sam
@Sam 这是一个更难的问题。我建议你进行研究,找到其他编写 API 的人所写的博客文章,看看哪种方法最好。我相信你可以在 GitHub 上找到一些相关项目。我没有做过太多的 API 工作,所以无法发表更多意见。 - loganfsmyth
我已经做了相当多的研究,但每个人在Node中似乎都有稍微不同的做事方式。我想我会按照这种方式去尝试,看看会发生什么,只要我的实现没有明显的错误,非常感谢。 - Sam
2
有时候我讨厌 JavaScript。虽然我理解'this'绑定到方法被调用的对象的方式,但有时它仍然是相当令人费解和自相矛盾的。 - Felipe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接