angular的注入实现

angular需要对用户的传入函数进行静态分析,抽取当中的依赖,才能工作。因此用户的函数,包括控制器函数,工厂函数,服务函数与$watch回调都只是一个模板,用于取toString,真正运行的是编译后的动态函数,有函数必须传参。比如:

function TestCtrl($scope){
     $scope.name = "xxx"
}

$scope就是一个很复杂的类的实例,angular内部有许多类,如何决定是放这个类的实例而不是其他类的呢。这就要看这参数长得什么样子,比如$scope肯定是作用域对象,$timeout就是定时器的。angular称之为依赖注入,而这个最简单的注入叫做推断式注入。实现很简单,取toString, 去掉函数名,去掉函数体,去掉参数名之间的注释与逗号,剩下就是一个字符串数组。但这东西是不抗压缩的。于是有其他两种注入:

标记注入:在控制器函数等上面添加一个叫$inject的属性,对应一个字符串数组,字符串不用说就是各种服务的名称。那么angular就会在取toString进行推断式注入前,先进行标记注入。


function TestCtrl(vm, timeout) {
    vm.friends = [{name: 'John', age: 25}, {name: 'Mary', age: 28}, {name: "Nasami", age: 30}
    timeout(function() {
        vm.friends.push({name: "add", age: 10})
    }, 1000)
}
TestCtrl.$inject = ["$scope", "$timeout"]

内联注入:我们在使用模块实例的factory,directive, filter或controller方法时,允许第二个传参是一个数组,这个数组最后一个元素为函数,其他元素为它所依赖的服务名称。这样对框架来说,抽取依赖更方便,但对用户来说,这传参也太奇诞了。


angular.module('myModule', [], function($provide) {
  $provide.factory('notify', ['$window', function(win) {
    var msgs = [];
    return function(msg) {
      msgs.push(msg);
      if (msgs.length == 3) {
        win.alert(msgs.join("
"));
        msgs = [];
      }
    };
  }]);
});

总之一句,IOC是angular为实现依赖收集被逼采取的一个非常恶心的做法,对比knockout,avalon就优雅多了。

原文地址:https://www.cnblogs.com/rubylouvre/p/3175759.html