10

在 AngularJS 中,这两个控制器声明是等价的:

function BlahCtrl($scope, $http) { ... }
function BlahCtrl($http, $scope) { ... }

无论它们的顺序如何$http,两者$scope都是正确的变量。即,命名的变量$http将始终传递给$http服务的实例。

Angular 是如何知道要传入哪些对象以及以什么顺序传入的?我认为这种反射在 javascript 中是不可能的。

4

2 回答 2

13

如果你调用toString一个函数,你会得到那个函数的 js 声明:

function a(b,c) {}

a.toString();  // "function a(b,c){}"

然后您可以解析字符串以获取参数的顺序。

对角度源代码的一些调查证实了这一点:

if (typeof fn == 'function') {
  if (!($inject = fn.$inject)) {
    $inject = [];
    fnText = fn.toString().replace(STRIP_COMMENTS, '');
    argDecl = fnText.match(FN_ARGS);
    forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
      arg.replace(FN_ARG, function(all, underscore, name){
        $inject.push(name);
      });
    });
    fn.$inject = $inject;
  }
}

他们对函数进行字符串化,然后使用正则表达式提取参数并将它们存储在数组中。

jsFiddle展示了这一切是如何工作的。

于 2012-08-20T01:39:31.073 回答
4

虽然我不知道他们是如何做到的,但有一种简单的方法可以做到。

JS 中的一切都有toString()方法。对于函数,它显示了该特定函数的源代码(对于内置函数,您可能会得到类似的东西function() { [native code] })。

让我们找到包含函数参数的 first(和 first 。)然后,让我们去掉空格并将参数拆分为,. 瞧,我们得到了一组参数名称。

function a($scope, $http) { };
function b($http, $scope) { };

function getParameterList(f) {
  var s = f.toString();

  var start = s.indexOf('(');
  var end = s.indexOf(')');

  s = s.substring(start + 1, end);

  return s.replace(/ /g,'').split(',');
}

所以让我们测试一下:

var aParams = getParameterList(a);
var bParams = getParameterList(b); 

alert(aParams[0]); // $scope
alert(aParams[1]); // $http 

alert(bParams[0]); // $http
alert(bParams[1]); // $scope  

小提琴:http: //jsfiddle.net/jYPB8/

但是,请注意,这种行为toString()是在中定义的,Function.prototype并且可能会被重新定义——在这种情况下,该算法将不起作用。

因此,虽然这可能不是您正在寻找的实际解决方案,但我想向您展示这种反射在 JavaScript 中可能的,而且实际上非常简单:)

于 2012-08-20T01:16:16.277 回答