class 定义中的闭包问题

Closure problems in class definition

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

这段代码有一个奇怪的问题。

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()

在这个简化的代码中,调用 handleResult 时出现错误 _Class.logout is not a function,错误代码为 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;

})());

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

有几种解决方法:

  • handleResult 设为私有实例变量,并将所有内容移动到构造函数中 - @get@logout 的声明也是如此。
  • handleResult一个你传递给@的实例参数,这样它就可以调用它的实例方法
  • 只调用 authErrorCallback 并执行 @logout 和里面的事情。

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

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

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"