1

所以我们都知道 'this' 在 JavaScript 中是一个棘手的关键字,而匿名函数和 AngularJS 承诺让它变得更加棘手。

问题(TL&DR 版本)

允许承诺回调使用与发起请求的服务相同的“this”的正确(和角度)方式是什么?

看这个小提琴的例子:

http://jsfiddle.net/tpeiffer/CFD3e/

控制器上的所有这些方法都调用了 Tier1Service。Tier1Service 然后调用 WorkerService 来获取数据。加载数据时,它通过向 Tier1Service 的承诺返回所述数据。返回的数据被设置到 Tier1Service_data 属性中。

替代 3 很干净并且有效,但感觉必须有更好的方法。

替代 4 也非常干净并且可以工作,但它似乎又是错误的。

现在我真正想要的是 $q 承诺为我做这一切。:)

以下是相关代码:

// App.js
    angular.constructor.prototype.call = function (scope, func) {
        return function () {
            func.apply(scope, arguments);
        };
    };

// Tier1Service
        get coolData() {
            return this._data;
        },
        set coolData(val) {
            this._data = val;
        },
        doWorkAlt1: function () {
            mySubWorkerService.someData.then(function (data) {
                // FAILS because 'this' is the window, 
                // not the service
                if (data) this._data = data;
            });
        },
        doWorkAlt2: function () {
            mySubWorkerService.someData.then((function (data) {
                // FAILS because data is undefined because
                // the function is wrapped in an anonymous
                // function
                if (data) this._data = data;
            }).call(this));
        },
        doWorkAlt3: function () {
            // WORKS because I keep track of the instance
            var instance = this;
            mySubWorkerService.someData.then(function (data) {
                if (data) instance._data = data;
            });
        },
        doWorkAlt4: function () {
            // WORKS because I keep pass 'this' around
            mySubWorkerService.someData.then(angular.call(this, function (data) {
                if (data) this._data = data;
            }));
        }

// WorkerService
        get someData() {
            var deferred = $q.defer();
            deferred.resolve('i got back data!!');
            return deferred.promise;
        }
4

1 回答 1

1

您应该能够使用Function.bind来实现您想要的结果:

doWork: function () {        
    mySubWorkerService.someData.then((function(data) {
        //this now refers to whatever it referred to in the doWork function
    }).bind(this));
}

但是请注意,这bind在旧版浏览器中不可用。但是,如果需要,很容易手动将其修补到原型中。

于 2013-09-02T15:37:10.730 回答