angularjs装饰器的使用
我们定义一个模块,并且配置一个configBlocks
1 | angular.module('myapp',[]).config(function($provide){ |
此处可以有几个疑问:
- config函数做了什么?
- decorator函数又做了什么?
- angular.element(document)为什么能获取injector?
config函数
1 | /* |
模块的config函数就是把参数configBlocks放入configBlocks数组中,然后在loadModules的时候
调用runInvokeQueue,获取$injectorProvider也就是instanceInjector后调用invoke函数,
传入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
### $provide.decorator函数
```js
function decorator(serviceName, decorFn) {
var origProvider = providerInjector.get(serviceName + providerSuffix),
orig$get = origProvider.$get;//是个字符串和函数的数组
origProvider.$get = function() { //相当于重新定义了原来的$get方法
var origInstance = instanceInjector.invoke(orig$get, origProvider);
return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
};
}
```
### $LogProvider
```js
$provide.provider({
$log: $LogProvider,
});
function $LogProvider() {
var debug = true,
self = this;
this.$get = ['$window', function($window) {
return {
log:consoleLog('log')
//省略部分代码
}
}]
}
```
执行decorator方法的时候先获取原来的$logProvider和它的$get属性,然后重新赋值$logProvider的
$get属性,把原来的$get属性放入新的$get函数内。
最终调用instanceInjector的getService方法获取,内部先从providerCache中获取后,再调用
对应$logProvider的新的$get函数,函数内部首先调用原先保存的旧的$get属性,获取原来的```{log:consoleLog('log')}```,
然后调用decorFn,传入```{$delegate: origInstance}```,最后就是对原来的$log实例的属性函数做了修改。
装饰器设计模式就是如此奇妙!
文章末尾彩蛋:
### $rootElement.data函数
在angular调用```doBootstrap```启动函数的时候,内部会调用```element.data('$injector', injector);
把创建好的instanceInjector放入element的data缓存中,所以能直接调用injector()函数,此部分的
源码设计我们会在之后的文章中进行剖析。