在下面的代码中,我收到"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
(并将函数作为隔离值调用(在这种情况下this
undefined
(。
修复实际上非常简单,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);
}
}
}