我们说我有以下两个指令:
angular.module('demo').directive('functional', [function (){
var idempotentMethods = ['idempotentMethod', 'otherIdempotentMethod'];
return {
restrict: 'E',
scope: {
'demoObject': '='
},
templateUrl: 'directive.html',
link: function (scope){
for(var i = 0; i < idempotentMethods.length - 1; i++){
scope[idempotentMethods[i]] = function(){
scope.demoObject[idempotentMethods[i]]();
}
}
}
}
}]);
angular.module('demo').directive('nonFunctional', [function (){
var idempotentMethods = ['idempotentMethod', 'otherIdempotentMethod'];
return {
restrict: 'E',
scope: {
'demoObject': '='
},
templateUrl: 'directive.html',
link: function (scope){
for(var i = 0; i < idempotentMethods.length; i++){
scope[idempotentMethods[i]] = scope.demoObject[idempotentMethods[i]];
}
}
}
}]);
以下工厂:
angular.module('demo').factory('demoFactory', ['$resource', function(resource){
var DemoFactory = resource('demo.json');
angular.extend(DemoFactory.prototype, {
idempotentMethod: function () {
return this.$get();
},
otherIdempotentMethod: function () {
return this.$get();
}
});
return DemoFactory;
}]);
在触发scope.idempotentMethod()的函数指令中(通过ng-click
或其他方式),将调用INCORRECT Factory方法。
在nonFunctional指令中触发
TypeError: undefined is not a function
at Scope.angular.extend.idempotentMethod
at $parseFunctionCall
at callback
at Scope.$eval
在工厂方法中。
这表明有两件事。
1)函数引用是绑定的(如预期的那样),但只有最后一个函数引用是绑定的。
2)this
引用不正确。在Factory方法中打印this
似乎证实了这一点,非功能性指令产生了Scope,而功能指令产生了一个资源。
造成这两种行为的原因是什么?为什么这个引用绑定不正确?为什么要调用错误的函数?
一位演示此问题的傻瓜:http://plnkr.co/B52DV0jmSWXc0M6GAamM
答案 0 :(得分:1)
我认为这是你设置闭包的方式:
function createBound(){
var fn = function(){console.log('this is:',this);}
,i = -1//ret items are set using the value i inside createBound
//by the time we call the function the value of i is 2
,ret = [];
for(i = 0; i < 2; i++){
ret.push(function(){
console.log('i is:',i);//says 2 every time
fn.call({hello:'world'});
});
}
return ret;
}
var bound = createBound();
bound[0]();
bound[1]();
正确的方法:
function createBound(){
var fn = function(){console.log('this is:',this);}
,i = -1
,ret = [];
for(i = 0; i < 2; i++){
ret.push(
(function(i,fn){//IIFE returning a function with correct i and fn
//the value of i and fn that are passed are used in the returned closure
//scope is within this IIFE, not within createBound
return function(){
console.log('i is:',i);//says: 0,1
fn.call({hello:'world'});
};
}(i,fn))//end of IIFE where i and fn are passed to create a new closure
);
}
return ret;
}
var bound = createBound();
bound[0]();
bound[1]();
<强> [UPDATE] 强>
在您的代码中传递正确的闭包,您可以这样做:
for(var i = 0; i < idempotentMethods.length - 1; i++){
scope[idempotentMethods[i]] = (function(i,idempotentMethods){
return function(){
scope.demoObject[idempotentMethods[i]]();
};
}(i,idempotentMethods));
}
请注意,当触发ng-click时,我不会指望idempotentMethods结束,这就是你的代码执行idempotentMethods[idempotentMethods.length-1]
的原因。