【问题标题】:route class not able to access local function #typescript #express路由类无法访问本地函数#typescript #express
【发布时间】:2017-08-19 08:36:20
【问题描述】:

在下面的代码中,“loglogMePleasePlease”函数出现“未定义”错误。

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

TypeError: 无法读取未定义的属性“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 typescript express


【解决方案1】:

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

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

class BindingTest {
  func() {
    console.log(this)
  }
}

const test = BindingTest()
const testFunc = test.func

现在,正如您在此示例中看到的那样,我们有 test 对象,它表示 func 方法,以及 testFunc 变量,它包含对该方法的引用。

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

因此,当我们运行以下命令时:

testFunc()

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

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

test.func()

我们打印了上下文!

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

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

const boundTestFunc = test.func.bind(test)

现在,如果我们去调用boundTestFunc,我们将得到我们期望的BindingTest 上下文打印出来。

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

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

【讨论】:

  • 感谢您的详细解释。帮助很大:)
【解决方案2】:

这可能是因为你的路由器弄乱了函数“default”的上下文,这就是为什么 this 等于 undefined。

您可以尝试在构造函数中将 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);
    }

}

【讨论】:

  • 这里有一个类似的问题stackoverflow.com/questions/15604848/…
  • 好建议丹尼尔,我将更新构造函数以接收路由器。 (感谢您的快速回答,我正要抓一大包“Lays Chips”来狂欢)
【解决方案3】:

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

server.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);
        });
    }

}

test.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);
        }
    }

}

【讨论】:

    猜你喜欢
    • 2015-05-12
    • 2016-06-22
    • 2019-04-03
    • 2022-12-04
    • 1970-01-01
    • 2021-03-14
    • 2019-09-22
    • 1970-01-01
    • 2021-04-01
    相关资源
    最近更新 更多