类定义中的闭包问题

时间:2015-08-31 09:47:48

标签: javascript coffeescript closures

我正在使用CoffeScript创建一个角度应用程序。

我对此代码有一个奇怪的问题。

webService.coffe(已简化)

ServiceManager.service "webService", class
    constructor : (@$http) ->

    # Private

    handleResult = (callback, errorCallback, authErrorCallback) =>
        (result) =>
            if result.result then callback result
            else
                if result.code is 102 then @logout authErrorCallback, errorCallback
                else errorCallback result.code, result.error

    get : (url, callback, errorCallback) ->
        @$http.get url
        .success handleResult callback, errorCallback, (=> @get url, callback, errorCallback)
        .error handleError errorCallback

    logout : (callback, errorCallback) ->
        @$http.get "logout"
        .success callback()
        .error errorCallback()

在这个简化的代码中,我在调用_Class.logout is not a function时收到错误handleResult,错误代码为102.

=>运营商应解决此问题,但事实并非如此。我不明白为什么......

javascript编译的webService.coffee代码

ServiceManager.service("webService", (function() {
  var handleResult;

  function _Class($http) {
    this.$http = $http;
  }

  handleResult = function(callback, errorCallback, authErrorCallback) {
    return function(result) {
      if (result.result) {
        return callback(result);
      } else {
        if (result.code === 102) {
          return _Class.logout(authErrorCallback, errorCallback);
        } else {
          return errorCallback(result.code, result.error);
        }
      }
    };
  };

  _Class.prototype.get = function(url, callback, errorCallback) {
    return this.$http.get(url).success(handleResult(callback, errorCallback, ((function(_this) {
      return function() {
        return _this.get(url, callback, errorCallback);
      };
    })(this)))).error(handleError(errorCallback));
  };

  _Class.prototype.logout = function(callback, errorCallback) {
    return this.$http.get("logout").success(callback()).error(errorCallback());
  };

  return _Class;

})());

1 个答案:

答案 0 :(得分:2)

您的问题是,您将handleResult定义为IIFE类中的静态私有变量。它无法访问@logout实例方法,因此CS会将其编译为无效的静态_Class.logout调用。

有几种解决方法:

  • 使handleResult成为私有实例变量,并在构造函数中移动所有内容 - @get@logout的声明。
  • handleResult一个你传递@的实例参数,以便它可以调用它上面的实例方法
  • 只调用authErrorCallback并执行@logout及其中的内容。

鉴于您的服务类无论如何都只会被实例化为一个单例,第一个可能是最明智的。

然而,无论如何,你真的应该考虑不要做那么复杂的回调。只需使用承诺:

ServiceManager.service "webService", class
    constructor : (@$http) ->

    get: (url) ->
        @$http.get url
        .then (result) =>
            if result.result then result
            else if result.code is 102 then @logout().then(=> @get url)
            else throw result.error

    logout: () ->
        @$http.get "logout"