应用于函数引用/范围的原型继承和函数引用

时间:2014-11-19 09:41:12

标签: javascript angularjs this pass-by-reference prototype-programming

我们说我有以下两个指令:

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

1 个答案:

答案 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]的原因。