AngularJS 'this' $timeout 函数中的引用无效

AngularJS 'this' reference in $timeout function not working

我有一个 AngularJS 问题快把我逼疯了。我有一个看起来像这样的服务(这是一个说明问题的例子)

var app = angular.module('test-module');

app.service('ToolService', function($timeout){

    this.doSomething = function() {
       console.log("y u no referenced as method?!?");
    }

    this.runTimeoutExample = function(){
        $timeout(function(){
            this.doSomething();
        }, 1000);
    }
})

我的控制器是这样的:

var app = angular.module('test-module', []);

var ctrl = app.controller('main-controller', function($scope, ToolService) {

    $scope.somethingWasClicked = function() {
        ToolService.runTimeoutExample();
    }

});

这是问题所在,当单击调用 $scope.somethingWasClicked 的按钮时,它会将调用转发给服务,但我收到一条错误消息 "this.doSomething is not a function"。

为什么?我该如何解决这个问题?我很难找到一种方法来绕过需要我的代码像这样 运行 而不向我的控制器添加不必要的逻辑。

提前感谢您的帮助

timeout 中的函数具有不同的作用域,因为它不是属于控制器的函数。在超时之前将 this 分配给一个变量,然后使用该变量:

var app = angular.module('test-module');

app.service('ToolService', function($timeout){

this.doSomething = function() {
   console.log("y u no referenced as method?!?");
}

this.runTimeoutExample = function(){
    var self = this;
    $timeout(function(){
        self.doSomething();
    }, 1000);
}
})

您有 2 个选择:

1) 使用函数对象的bind()方法:

更改超时回调的上下文,到达控制器this:

this.runTimeoutExample = function(){
    $timeout(function(){
        this.doSomething();
    }.bind(this), 1000);
}

2) 创建一个特殊变量self,以保持link到主服务函数上下文:

var app = angular.module('test-module');

app.service('ToolService', function($timeout){
    var self = this;     
    self.doSomething = function() {
       console.log("y u no referenced as method?!?");
    }

    self.runTimeoutExample = function(){
        $timeout(function(){
            self.doSomething();
        }, 1000);
    }
})

如果每次都使用 self,您将确保不会发生上下文丢失。

Read more 关于函数的上下文。

var app = angular.module('test-module',[]);

app.service('ToolService', function($timeout){

   function doSomething() {
       console.log("y u no referenced as method?!?");
    }

    this.runTimeoutExample = function(){
        $timeout(function(){
           doSomething();
        }, 1000);
    }
});
 app.controller('main-controller', function($scope, ToolService) {
   
    $scope.somethingWasClicked = function() {
    
        ToolService.runTimeoutExample();
    };

});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test-module" ng-controller="main-controller">
  
  <input type="button" value="click" ng-click="somethingWasClicked()">
  
  </div>