javascript - 为什么变量在方法中未定义,但在 Typescript 的构造函数中却没有定义

标签 javascript angularjs typescript

我正在使用 1.4.9 Angularjs 和 Typescript 开发一个应用程序。

我有一个注入(inject)了 testManagementService 服务的 Controller , testManagementService 变量是构造函数中的一个对象,但在调用它的方法中未定义。奇怪的是,我在另一个 Controller 中使用另一个服务进行了相同的设置,并且工作正常。

问题:

  • 构造函数中有一个带有 testmgmgservice 标签的 console.log,它表示 testManagementService 变量是一个具有 getTestSuiteTree 方法的 Restangular 对象
  • 由 kendo.data.TreeListDataSource 调用/管理的 readRepository 方法中的控制台日志显示 this.testManagementService 未定义。

enter image description here

到目前为止我做了什么:

  • 我已经检查了语法,可能我错过了一些东西 --> 不
  • 我已将变量名称更改为不同的内容,以检查是否有其他变量覆盖它 --> 相同的结果
  • 我睡了很长时间,有时有帮助 --> 没有新想法
  • 我用 Vs2013 和 VS2015 编译了代码 --> 结果相同

服务:

module sayusiando.gonogo.web.spa.service {
    import IGeneralTestSuitTestCaseContract = sayusiando.gonogo.web.spa.common.contracts.IGeneralTestSuitTestCaseContract;
    "use strict";

    export interface ITestManagementService {

        getTestSuitTree(): ng.IPromise<IGeneralTestSuitTestCaseContract[]>;

    }

    class TestManagementService implements ITestManagementService {

        //#region ctor
        constructor(
            private Restangular: restangular.IService
        ) { }
        //#endregion

        public getTestSuitTree(): ng.IPromise<IGeneralTestSuitTestCaseContract[]> {

            var resource = this.Restangular.all("TestSuite/GetTestSuiteTree");

            return <any>resource.getList();

        }

    }

    factory.$inject = ["Restangular"];

    function factory(Restangular: restangular.IService) {
        return new TestManagementService(Restangular);
    }

    angular
        .module("goNoGo")
        .factory("testManagementService", factory);

}

Controller :

module sayusiando.gonogo.web.spa.mainpage.showtestsuittree.controllers {
    import IGeneralTestSuitTestCaseContract = sayusiando.gonogo.web.spa.common.contracts.IGeneralTestSuitTestCaseContract;
    import DataSourceTransport = kendo.data.DataSourceTransport;
    import DataSourceSchema = kendo.data.DataSourceSchema;
    import DataSourceSchemaModelFields = kendo.data.DataSourceSchemaModelFields;
    import TestManagementService = sayusiando.gonogo.web.spa.service.ITestManagementService;
    "use strict";

    export interface IShowTestSuitTreeController {
        activate: () => void;
    }

    class ShowTestSuitTreeController implements IShowTestSuitTreeController {

        //#region Variables
        testSuiteTree = [];
        testSuiteTreeKendoTreeListOptions: kendo.ui.TreeListOptions = {};
        //#endregion

        //#region Inject and ctor
        static $inject: string[] = ['testManagementService'];

        constructor(
            private testManagementService: gonogo.web.spa.service.ITestManagementService
        ) {

            console.log('testmgmgservice', testManagementService);

            this.activate();

        }
        //#endregion

        activate(): void {

            var dataSourceTransport = <DataSourceTransport>{
                read: this.readRepository
            };

            var schema: DataSourceSchema = <DataSourceSchema>{
                model: {
                    id: "id",
                    parentId: "parentId",
                    fields: <DataSourceSchemaModelFields>{

                        id: { type: "number", editable: false, nullable: true },
                        name: { type: "string", editable: false, nullable: true }

                    }

                }

            };

            var dataSource = new kendo.data.TreeListDataSource({
                transport: dataSourceTransport,
                schema: schema,
                batch: true
            });


            var idColumn: kendo.ui.TreeListColumn = <kendo.ui.TreeListColumn>{
                field: "id",
                width: "100px"
            };
            var nameColumn: kendo.ui.TreeListColumn = <kendo.ui.TreeListColumn>{
                field: "name",
                width: "400px"
            };

            this.testSuiteTreeKendoTreeListOptions.dataSource = dataSource;
            this.testSuiteTreeKendoTreeListOptions.sortable = false;
            this.testSuiteTreeKendoTreeListOptions.editable = false;
            this.testSuiteTreeKendoTreeListOptions.columns = [
                idColumn,
                nameColumn
            ];

        }

        readRepository(e): any {

            console.log('testmgmt2', this.testManagementService);
            this.testManagementService.getTestSuitTree().then((result: Array<IGeneralTestSuitTestCaseContract>): void => {
                e.success(result);
            }, (reason: any): void => {
                e.error(reason);
            });

            return e;
        }

    }

    angular
        .module("goNoGo")
        .controller("showTestSuitTreeController", ShowTestSuitTreeController);
}

从 Controller 生成的 JavaScript:

var sayusiando;
(function (sayusiando) {
    var gonogo;
    (function (gonogo) {
        var web;
        (function (web) {
            var spa;
            (function (spa) {
                var mainpage;
                (function (mainpage) {
                    var showtestsuittree;
                    (function (showtestsuittree) {
                        var controllers;
                        (function (controllers) {
                            "use strict";
                            var ShowTestSuitTreeController = (function () {
                                function ShowTestSuitTreeController(testManagementService) {
                                    this.testManagementService = testManagementService;
                                    //#region Variables
                                    this.testSuiteTree = [];
                                    this.testSuiteTreeKendoTreeListOptions = {};
                                    console.log('testmgmgservice', testManagementService);
                                    this.activate();
                                }
                                //#endregion
                                ShowTestSuitTreeController.prototype.activate = function () {
                                    var dataSourceTransport = {
                                        read: this.readRepository
                                    };
                                    var schema = {
                                        model: {
                                            id: "id",
                                            parentId: "parentId",
                                            fields: {
                                                id: { type: "number", editable: false, nullable: true },
                                                name: { type: "string", editable: false, nullable: true }
                                            }
                                        }
                                    };
                                    var dataSource = new kendo.data.TreeListDataSource({
                                        transport: dataSourceTransport,
                                        schema: schema,
                                        batch: true
                                    });
                                    var idColumn = {
                                        field: "id",
                                        width: "100px"
                                    };
                                    var nameColumn = {
                                        field: "name",
                                        width: "400px"
                                    };
                                    this.testSuiteTreeKendoTreeListOptions.dataSource = dataSource;
                                    this.testSuiteTreeKendoTreeListOptions.sortable = false;
                                    this.testSuiteTreeKendoTreeListOptions.editable = false;
                                    this.testSuiteTreeKendoTreeListOptions.columns = [
                                        idColumn,
                                        nameColumn
                                    ];
                                };
                                ShowTestSuitTreeController.prototype.readRepository = function (e) {
                                    console.log('testmgmt2', this.testManagementService);
                                    this.testManagementService.getTestSuitTree().then(function (result) {
                                        e.success(result);
                                    }, function (reason) {
                                        e.error(reason);
                                    });
                                    return e;
                                };
                                //#endregion
                                //#region Inject and ctor
                                ShowTestSuitTreeController.$inject = ['testManagementService'];
                                return ShowTestSuitTreeController;
                            })();
                            angular
                                .module("goNoGo")
                                .controller("showTestSuitTreeController", ShowTestSuitTreeController);
                        })(controllers = showtestsuittree.controllers || (showtestsuittree.controllers = {}));
                    })(showtestsuittree = mainpage.showtestsuittree || (mainpage.showtestsuittree = {}));
                })(mainpage = spa.mainpage || (spa.mainpage = {}));
            })(spa = web.spa || (web.spa = {}));
        })(web = gonogo.web || (gonogo.web = {}));
    })(gonogo = sayusiando.gonogo || (sayusiando.gonogo = {}));
})(sayusiando || (sayusiando = {}));
//# sourceMappingURL=showTestSuitTreeController.js.map

最佳答案

我很确定问题是您在此处将函数引用传递给框架:

  var dataSourceTransport = <DataSourceTransport>{
      read: this.readRepository
  };

这样做,你就会失去上下文(this)。当库调用您的 readRepository 函数时,它不再适用于您事先定义该函数的上下文。因此,当调用该函数时,testManagementService 不存在于 this 上。

您可以通过绑定(bind)到正确的上下文来解决此问题,如下所示:

  var dataSourceTransport = <DataSourceTransport>{
      read: this.readRepository.bind(this)
  };

或者在传递引用时使用箭头函数捕获它

  var dataSourceTransport = <DataSourceTransport>{
      read: (e) => this.readRepository(e)
  };

或者通过使回调本身成为箭头函数,保持注册不变。请注意其中的含义,因为该函数不再在原型(prototype)上注册。

readRepository = (e) => {
    ...
}

了解更多信息,请查看https://basarat.gitbooks.io/typescript/content/docs/arrow-functions.html

关于javascript - 为什么变量在方法中未定义,但在 Typescript 的构造函数中却没有定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35670081/

相关文章:

javascript - npm zombie 将<head>内容放入<body>中

javascript - 如何使用 DoCheck 在月份选择器上反射(reflect)/突出显示手动输入的月份 [Angular]

javascript - 如何优化 async.js API 调用?

javascript - 如何使用父对象中对每个子对象的 ID 引用将主对象与子对象合并

angularjs - ng-include 与 ui-router 中的 $state.go() 不起作用

javascript - 参数 'meetupsController' 不是函数,出现未定义错误

javascript - jquery 动画幻灯片放映不动画

javascript - window.open 指向自身而不是其他页面

javascript - TypeScript 编译错误

html - ionic 2 : Dismiss loading animation when iframe is ready