caoruiy‘s blog

Wisdom outweighs any wealth

Angular-API-auto-service-$injector

$injector

service in module auto

$injector 用于检索由provider定义的对象实例,实例化类型,调用方法和加载模块。

以下的示例总是成立:

var $injector = angular.injector();

expect($injector.get('$injector')).toBe($injector);

expect($injector.invoke(function($injector) {
  return $injector;
})).toBe($injector);

angular.injector()可以调用多次,每次都返回新建的injector对象。,所以以上示例总是成立

angular提供了三种依赖注入的方式,下面以示例说明:

// 创建myModule模块、注册服务  
var myModule = angular.module('myModule', []);  
myModule.service('myService', function() {  
            this.my = 0;  
});  

// 获取injector/注入器  
var injector = angular.injector(["myModule"]);  

// 第一种inference  / 推断式注入
// 推断式注入是不需要事先声明我要使用哪些服务,只需要写上你要使用的服务名称,angular会自动把该服务注入到我们的函数中
injector.invoke(function(myService){alert(myService.my);});  

// 第二种annotation  / 注释式注入
// 首先声明调用服务的函数,函数形参中引用该服务,形成名称可以是任意值
// 因为下一步需要注释我引用的服务到底叫什么名字
// 最后invoke使用该服务
function explicit(serviceA) {alert(serviceA.my);};  
explicit.$inject = ['myService'];  
injector.invoke(explicit);  

// 第三种inline  / 内联式注入
// 注入服务时,首先在数组中声明要使用的服务,然后使用该服务
injector.invoke(['myService', function(serviceA){alert(serviceA.my);}]);  

以上三种方式第三种方式内联式注入最为合理,因为他是第二种注释式注入的简化形式。同时他与第一种方式的区别在于推断式注入只是通过形参名称来判断注入的服务,如果代码通过压缩工具压缩代码后,形参被改变,代码将无法工作,内联式注入可以解决这个问题。行为函数形参可以是任意值。

Inference

在JavaScript中调用toString()函数返回函数定义。 然后可以解析定义,并提取函数参数。 当注射器处于严格模式时,不允许注释式注这种方法

注意:这不适用于缩小和混淆工具,因为这些工具更改了参数名称。

inject 注入 / annotation 注入

通过添加$inject属性到一个功能可以指定注入参数。

Inline

作为注入名称的数组,其中数组中的最后一个项是要调用的函数


// 下列所有示例都依赖于该模块服务
let serv = angular.module('serv',[])

serv.service('first', function(){
    this.age = 10
})

方法

注:请把下面所有示例中的 angular.injector(['serv'])当成$injector,该$injector是一个服务,可以在控制器中引入,所有示例请写在某控制器中运行。

get(name, [caller]);

返回服务的实例

  • name : string : 要检索的实例的名称
  • caller(optional) : string : 一个可选的字符串,为错误消息提供函数调用的原点。
angular.injector(['serv']).get('first', 'error message'); // Object {age: 10}
// 如果调用的服务不存在,则会报错,第二个参数的信息会被包含在报错信息中
angular.injector(['serv']).get('first', 'error message'); // 以下报:位置服务错误
// angular.js:4789 Uncaught Error: [$injector:unpr] Unknown provider: firstsProvider <- firsts <- error message(…)
返回值

* : The instance。服务实例。

invoke(fn, [self], [locals]);

调用方法并从$injector提供方法参数。

注:从该方法调用服务

  • fn : function / Array.<(string|function)> :要注入的注入函数。 函数参数根据$inject注释规则注入。

  • self(optional) : Object : The this for the invoked method。该方法的上下文 this,方法内的this都指向该self

  • locals(optional) : Object : 可选对象。 如果预设,则在查询$injector之前,首先从该对象读取任何可用的参数名称。

angular.injector(['serv']).invoke(['serv','others',function(serv, others){
    // TODO
}], self, locals)

has(name)

允许用户查询特定服务是否存在。

  • name : string : 服务名称
Returns

boolean true if injector has given service.

instantiate(Type, [locals])

创建一个JS类型的新实例。该方法接受构造函数,调用new运算符,并将所有locals指定的参数提供给构造函数。

  • Type : function : 构造函数的函数说明。
  • locals(optional) : Object : 可选对象。 如果预设,则在查询$injector之前,首先从该对象读取任何可用的参数名称。
angular.injector(['serv']).instantiate(function(serv){
    console.log(serv);
},['serv'])

Returns

Object new instance of Type.

annotate(fn, [strictDi])

返回函数请求注入的服务名称数组。 注入器使用此API确定在调用函数时需要将哪些服务注入到函数中。 有三种方法可以用所需的依赖来注释函数。

说白了,该方法可用返回函数的形参列表,因为在依赖注入的推断式注入就是根据该方法确定的形参列表来确定注入哪些服务。

  • fn : function()Array.<(string|function())> : 需要如上所述检索依赖服务名称的函数。
  • strictDi(optional) : boolean : 不允许参数名称注释推断。(默认值:false)
// 推断式
angular.injector(['serv']).annotate(function($scope, $rootScope){}); // [$scope, $rootScope]

// inject式
function myService(scope, rootScope){}
myService.$inject = ['$scope', '$rootScope'];
angular.injector().annotate(myService); // [$scope, $rootScope]

// inline 内联式
angular.injector().annotate(['$scope', '$rootScope', function(scope, rootscope){}]);  // [$scope, $rootScope]
Returns

Array. The names of the services which the function requires. 函数需要的服务的名称所组成的数组。

Argument names

最简单的形式是从函数的参数中提取依赖关系。这是通过使用toString()方法将函数转换为字符串并提取参数名称来完成的。

// Given
function MyController($scope, $route) {
  // ...
}

// Then
expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);

在严格的注射器模式下,你可以禁用该方法。

因为该方法不能再压缩和代码混淆的情况下工作,你可以使用“注释式注入”和“内联式注入”。

var app = angular.module('test',[]);

app.service('ser',function(){
    this.name = 'ser'
})
// 控制器 frist
app.controller('first',['$scope','$injector',
    function($scope, $injector){
        function he(ser){
            console.log(ser)
        }
        // 注释式注入
        he['$inject']=['ser'];
        $injector.invoke(he);
        // 内联式注入
        $injector.invoke(['ser',function(ser){}])
    }])

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注