路由类无法访问本地函数 #typescript #express



在下面的代码中,我收到"loglogMePleasePlease"函数的"未定义"错误。

有人可以帮我解决这个问题吗?

类型错误: 无法读取未定义的属性"logMePleasePlease">

我很惊讶,这种错误让我质疑到目前为止我编码的所有内容

import {Router, Request, Response, NextFunction} from 'express';
import * as fs from 'fs';
import { db } from '../db/lowDb'
export class employeeRoute {
router: Router
constructor() {
this.router = Router();
this.init();
}
init() {
this.router.get('/', this.default);
this.logMePleasePlease('SFDSFSDF');/*This call works fine!*/
}
public logMePleasePlease(err){
console.log(err);
}
public default(req: Request, res: Response, next: NextFunction) {
/*****Error when execution gets to follwing line:
TypeError: Cannot read property 'logMePleasePlease' of undefined
******/
this.logMePleasePlease('asdad');
res.send({
status:'ok',
message:'employee api home'
});
}
}
const employee = new employeeRoute();
export default employee.router;

这是由 JavaScript 在调用函数时绑定this的方式引起的。

让我们举几个例子,说明我的意思以及如何修复它。

class BindingTest {
func() {
console.log(this)
}
}
const test = BindingTest()
const testFunc = test.func

现在,正如你在这个例子中看到的,我们有呈现func方法的test对象,以及保存对该方法的引用的testFunc变量。

重要的是要记住JavaScript移动值(并向类添加函数(的方式,特别是一切都是值。在这种情况下,当我们赋值const testFunc = test.func时,我们所做的是获取BindingTest.prototype.func值(我们在类上定义的函数(并直接引用它。

因此,当我们运行以下内容时:

testFunc()

我们将看到它打印出undefined而不是BindingTest上下文......

这很奇怪,因为当我们运行以下内容时:

test.func()

我们打印上下文!

因此,正如我所提到的,这是通过对象的原型调用策略调用函数的结果(在这种情况下,this绑定到test(并将函数作为隔离值调用(在这种情况下thisundefined(。

修复实际上非常简单,JavaScript 提供了.bind()方法,允许您将this上下文与函数值相关联。

const boundTestFunc = test.func.bind(test)

现在,如果我们去打电话给boundTestFunc,我们将按照我们的预期打印出我们的BindingTest上下文。

我希望这能澄清你所看到的背后的"原因"。在您的情况下:解决方法是简单地在构造函数中使用以下代码。

this.router.get('/', this.default.bind(this));

这可能是因为您的路由器搞砸了函数"default"的上下文,这就是为什么这等于未定义。

您可以尝试将 func 绑定到构造函数中的正确上下文:

this.default.bind(this)

但这很混乱。您确定为每个路由配备一个单独的路由器是个好主意吗?我将创建唯一的路由器并将其提供给构造函数中的每个路由类。

我习惯于遵循模式来创建来自一个流行教程的路由,由于广泛使用静态方法,这有点争论,但对我来说效果很好:

import { NextFunction, Request, Response, Router } from 'express'

export class IndexRoute {

static CREATE(router: Router) {
console.log('[IndexRoute::create] Creating route /');
router.get('/', (req, res, next) => {
new IndexRoute().index(req, res, next)
})
}

index(req: Request, res: Response, next: NextFunction) {
console.log('[IndexRoute::index]');
const data = { status: 'ok' };
res.status(200).json(data);
}
}

如果这对任何人有帮助,这里是在Router上使用类和use方法的示例代码(请参阅此处文档底部的示例(。

服务器.ts

import { Test } from './test';
import express from "express";
import compression from "compression";
export class Server {
private app: express.Application;
private port: number = 3000;
private test: Test;
constructor() {
// setup server
this.app = express();
this.app.use(express.urlencoded({ extended: true }));   // needed for POST requests
this.app.use(express.json());   // needed for POST requests
this.app.use(compression());
// create classes
this.test = new Test();
// tell app to use routes
this.app.use("/test", this.test.router);
// start listening
this.app.listen(this.port, () => {
console.log("Node Express server listening on port " + this.port);
});
}
}

测试.ts

import express, { Router, Request, Response } from "express";
export class Test {
public router: Router = express.Router();
private testVar: string = "Hello World";
constructor() {
this.router.get('/', [this.get.bind(this)]);
}
private async get(req: Request, res: Response) {
try {
// return
res.status(200).send(this.testVar);
} catch (error) {
res.status(500).send(error);
}
}
}

最新更新