AngularJS 依赖注入的实现

Posted by cl9000 on May 18, 2020

预测未来最好的方法就是去创造未来。——<亚伯拉罕·林肯>

文章来源:https://bdadam.com/blog/demistifying-angularjs-dependency-injection.html

很多人认为 AngularJS 是如何解析作为函数参数的依赖关系的,这是一种魔法。但这不是什么魔法。我来告诉你,他们是怎么做到的。这种技术可以在任何地方使用,而不仅仅是AngularJS

如果你不知道 AngularJS 中的依赖注入是什么样的,下面是一个例子:

1
2
3
4
5
6
7
8
9
<div ng-controller="GreetCtrl">
Hello !
</div>
<script>
function GreetCtrl($scope, $rootScope) {
$scope.name = 'World';
$rootScope.department = 'Angular';
}
</script>

我们只需要把 $scope$rootScope 放入函数参数中,当 Angular调用控制器(GreetCtrl)时,它知道需要使用参数来调用函数。

它是怎么做到的?

JavaScript中很容易获得每个函数的源代码。我们只需调用函数对象的 .tostring()方法。

1
2
3
4
5
function sum(x, y) {
alert(x + y);
}

console.log(sum.toString()); // prints the complete code of the function

看下面,我们只需要找到一种方法来提取函数的参数列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// The following simplified code is partly taken from the AngularJS source code:
// https://github.com/angular/angular.js/blob/master/src/auto/injector.js#L63

function inject(fn, variablesToInject) {
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;

if (typeof fn === 'function' && fn.length) {
var fnText = fn.toString(); // getting the source code of the function
fnText = fnText.replace(STRIP_COMMENTS, ''); // stripping comments like function(/*string*/ a) {}

var matches = fnText.match(FN_ARGS); // finding arguments
var argNames = matches[1].split(FN_ARG_SPLIT); // finding each argument name

var newArgs = [];
for (var i = 0, l = argNames.length; i < l; i++) {
var argName = argNames[i].trim();

if (!variablesToInject.hasOwnProperty(argName)) {
// the argument cannot be injected
throw new Error("Unknown argument: '" + argName + "'. This cannot be injected.");
}

newArgs.push(variablesToInject[argName]);
}

fn.apply(window, newArgs);
}
}

function sum(x, y) {
console.log(x + y);
}

inject(sum, {
x: 5,
y: 6
}); // should print 11

inject(sum, {
x: 13,
y: 45
}); // should print 58

inject(sum, {
x: 33,
z: 1 // we are missing 'y'
}); // should throw an error: Unknown argument: 'y'. This cannot be injected.

所以这真的没什么大不了的,不是吗?

参考

关注【公众号】,了解更多。



支付宝打赏 微信打赏

赞赏一下 坚持原创技术分享,您的支持将鼓励我继续创作!