在 AngularJS 中,这两个控制器声明是等价的:
function BlahCtrl($scope, $http) { ... }
function BlahCtrl($http, $scope) { ... }
无论它们的顺序如何$http
,两者$scope
都是正确的变量。即,命名的变量$http
将始终传递给$http
服务的实例。
Angular 是如何知道要传入哪些对象以及以什么顺序传入的?我认为这种反射在 javascript 中是不可能的。
在 AngularJS 中,这两个控制器声明是等价的:
function BlahCtrl($scope, $http) { ... }
function BlahCtrl($http, $scope) { ... }
无论它们的顺序如何$http
,两者$scope
都是正确的变量。即,命名的变量$http
将始终传递给$http
服务的实例。
Angular 是如何知道要传入哪些对象以及以什么顺序传入的?我认为这种反射在 javascript 中是不可能的。
如果你调用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展示了这一切是如何工作的。
虽然我不知道他们是如何做到的,但有一种简单的方法可以做到。
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 中是可能的,而且实际上非常简单:)