为什么'这个#39;指的是x#39; window'在这个TypeScript片段?

时间:2015-01-09 23:49:07

标签: javascript angularjs typescript

鉴于这段代码:

module movieApp {
    export interface IHomeControllerScope extends ng.IScope {
        moviesToDownload: string[];
        active: string;

        deleteMovieFromDownloadList(movie: any);

        markMovieAsDownloaded(movie: any);
    }

    export class HomeController {
        public static $inject = [
            '$scope',
            '$location',
            'MovieService'
        ];

        constructor(private $scope: IHomeControllerScope, private $location: ng.ILocationService, private MovieService) {
            this.$scope.$on('$locationChangeSuccess', (event) => {
                this.setActiveUrlPart();
            });

            MovieService.getMoviesToDownload().then(response => {
                this.$scope.moviesToDownload = response;
            });
        }

        private setActiveUrlPart() {
            var parts = this.$location.path().split('/');
            this.$scope.active = parts[1];
        }

        public get moviesToDownload() {
            return this.$scope.moviesToDownload;
        }

        public markMovieAsDownloaded(movie: any) {
            movie.Downloaded = true;
        }

        public deleteMovieFromDownloadList(movie: any) {
            this.MovieService.deleteMovieFromDownloadList(movie).then(() => {
                debugger;
                this.$scope.moviesToDownload = _.without(this.$scope.moviesToDownload, movie);
            });
        }
    }
}

app.controller("HomeController", movieApp.HomeController);

一切正常,但在行deleteMovieFromDownloadList中的方法this.$scope.moviesToDownload = _.without(this.$scope.moviesToDownload, movie);中,this指的是窗口对象,而不是我期望的实际对象。

生成的JavaScript如下所示:

var movieApp;
(function (movieApp) {
    var HomeController = (function () {
        function HomeController($scope, $location, MovieService) {
            var _this = this;
            this.$scope = $scope;
            this.$location = $location;
            this.MovieService = MovieService;
            this.$scope.$on('$locationChangeSuccess', function (event) {
                _this.setActiveUrlPart();
            });

            MovieService.getMoviesToDownload().then(function (response) {
                _this.$scope.moviesToDownload = response;
            });
        }
        HomeController.prototype.setActiveUrlPart = function () {
            var parts = this.$location.path().split('/');
            this.$scope.active = parts[1];
        };

        Object.defineProperty(HomeController.prototype, "moviesToDownload", {
            get: function () {
                return this.$scope.moviesToDownload;
            },
            enumerable: true,
            configurable: true
        });

        HomeController.prototype.markMovieAsDownloaded = function (movie) {
            movie.Downloaded = true;
        };

        HomeController.prototype.deleteMovieFromDownloadList = function (movie) {
            var _this = this;
            this.MovieService.deleteMovieFromDownloadList(movie).then(function () {
                debugger;
                _this.$scope.moviesToDownload = _.without(_this.$scope.moviesToDownload, movie);
            });
        };
        HomeController.$inject = [
            '$scope',
            '$location',
            'MovieService'
        ];
        return HomeController;
    })();
    movieApp.HomeController = HomeController;
})(movieApp || (movieApp = {}));

app.controller("HomeController", movieApp.HomeController);
//# sourceMappingURL=HomeController.js.map

如您所见,在生成的JS中,特定方法使用_this。这看起来是对的,对吧?

有人可以向我解释会发生什么以及如何解决这个问题吗?

编辑:

我将它与Angular结合使用:

<body data-ng-app="movieApp" data-ng-controller="HomeController as homeCtrl">
  <div class="col-sm-1">
    <i class="fa fa-trash-o" data-ng-click="homeCtrl.deleteMovieFromDownloadList(m)" title="Verwijder uit lijst"></i>
  </div>
</body>

编辑II: 在尝试了所有建议然后回放我在这里发布的原始代码之后,一切正常!我不知道怎么做,但我想这与Chrome / VS 2013有关。无论如何,感谢那些试图帮助我的人。

3 个答案:

答案 0 :(得分:2)

我猜测问题在于如何调用deleteMovieFromDownloadList。如果您这样做:

var myController = new HomeController();
someFramework.doSomethingWithCallback(myController.deleteMovieFromDownloadList);

... someFramework最终会调用回调,而不会将其绑定到预期的上下文。如果是这种情况,您可以通过执行以下操作来解决此问题:

var boundCallback = myController.deleteMovieFromDownloadList.bind(myController);
someFramework.doSomethingWithCallback(boundCallback);

<强>更新

在阅读Angular文档时,您在点击处理程序中放置的内容似乎并非真正的JavaScript,而是由Angular解释。所以也许homeCtrl.deleteMovieFromDownloadList(m)正在做这样的事情:

var fn = homeCtrl.deleteMovieFromDownloadList;
fn(m):

...当然不能正确设置this

设置控制器后,你不能这样做吗?

data-ng-click="deleteMovieFromDownloadList(m)"

答案 1 :(得分:2)

可能“deleteMovie ...”函数绑定到按钮或其他UI元素。在这种情况下,此函数在窗口上下文中执行。要解决此问题,您应该在控制器的构造函数中定义函数体:

constructor(private $scope: IHomeControllerScope, private $location: ng.ILocationService, private MovieService) {
// other initialization code...

this.deleteMovieFromDownloadList = (movie: any) => {
    this.MovieService.deleteMovieFromDownloadList(movie).then(() => {
        debugger;
        this.$scope.moviesToDownload = _.without(this.$scope.moviesToDownload, movie);
    });
  }
}

并在控制器类中声明适当的函数:

deleteMovieFromDownloadList: (movie: any) => void;

答案 2 :(得分:1)

Javascript在构造函数方面有一些奇怪的行为。我举了一个例子来告诉你它是如何工作的:

function myClass() {
    var me = this;
    this.property = 'test';
    this.windowObj = function() {
        windowObjTest();
    }

    var windowObjTest = function() {
        console.log(this); // this = window object
    }

    this.myself = function() {
        myselfTest();
    }

    var myselfTest = function() {
        console.log(me); // me = this object
    }
}

var myobj = new myClass();
myobj.windowObj();
myobj.myself();

this.windowObj();是一个调用私有函数windowObjTest();的公共函数。在私有函数中,this是对窗口对象的引用,而不是对此实例的引用(不要问我,dev是高还是什么......)。要将当前对象的引用转换为私有函数,必须将当前对象的引用设置为构造函数:var me = this;

尝试示例并查看控制台。应出现两个条目:

- Window test.php //console.log(this);
- myClass { property="test", windowObj=function(), myself=function()} //console.log(me);