在Angular.js中可以注入什么“东西”?

我很难理解Angular中的依赖注入。 所以我的问题是,任何人都可以解释哪些“类型”,如控制器,工厂,提供者等我们可以注入到其他人,包括相同的“类型”的其他实例?

我实际上正在寻找的是这张桌子里充满了y / n。 对于具有相同行/列的单元格,这意味着将一个“类型”的值注入另一个具有相同“类型”

+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Can we inject? | Constant | Controller | Directive | Factory | Filter | Provider | Service | Value |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Constant       |          |            |           |         |        |          |         |       |
| Controller     |          |            |           |         |        |          |         |       |
| Directive      |          |            |           |         |        |          |         |       |
| Factory        |          |            |           |         |        |          |         |       |
| Filter         |          |            |           |         |        |          |         |       |
| Provider       |          |            |           |         |        |          |         |       |
| Service        |          |            |           |         |        |          |         |       |
| Value          |          |            |           |         |        |          |         |       |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+

相反,只是在没有任何解释的情况下填写“是”和“否”,我会详细介绍一下。

[注意,在完成后添加:这最终会比我预期的时间长得多。 底部有一个tl博士,但我希望这证明了信息。]

[这个答案也被添加到AngularJS wiki中:理解依赖注入]


提供者( $provide

$provide服务负责告诉Angular如何创建新的注射物; 这些东西被称为服务 。 服务由所谓的供应商定义,这就是您在使用$provide时创建的内容。 定义提供者是通过$provide服务上的$provide provider方法完成的,您可以通过要求将它注入到应用程序的config函数中来获得$provide服务。 一个例子可能是这样的:

app.config(function($provide) {
  $provide.provider('greeting', function() {
    this.$get = function() {
      return function(name) {
        alert("Hello, " + name);
      };
    };
  });
});

这里我们已经定义了一个名为greeting的服务的新提供者; 我们可以将一个名为greeting的变量注入到任何可注入的函数中(比如控制器,稍后会介绍更多),而Angular会调用提供者的$get函数以返回一个新的服务实例。 在这种情况下,将被注入的东西是一个函数,该函数根据name采用name参数并alert sa消息。 我们可以像这样使用它:

app.controller('MainController', function($scope, greeting) {
  $scope.onClick = function() {
    greeting('Ford Prefect');
  };
});

这里有个诀窍。 factoryservicevalue都是定义提供者各个部分的捷径 - 也就是说,他们提供了一种定义提供者的方法,而不必输入所有的东西。 例如,您可以像这样编写完全相同的提供程序

app.config(function($provide) {
  $provide.factory('greeting', function() {
    return function(name) {
      alert("Hello, " + name);
    };
  });
});

理解这一点非常重要,所以我会重申:在底层,AngularJS正在调用与我们上面编写的完全相同的代码$provide.provider版本)。 从字面上看,两个版本100%没有区别。 value工作方式是一样的 - 如果我们从$get函数(即我们的factory函数)返回的内容总是完全相同,那么我们可以使用value编写更少的代码。 例如,因为我们总是为我们的greeting服务返回相同的功能,所以我们也可以使用value来定义它:

app.config(function($provide) {
  $provide.value('greeting', function(name) {
    alert("Hello, " + name);
  });
});

同样,这与我们用来定义此函数的其他两种方法完全相同 - 它只是一种保存某些输入的方法。

现在你可能已经注意到这个恼人的app.config(function($provide) { ... })我一直在使用的东西。 由于定义新的提供者(通过上述任何给定的方法)非常常见,AngularJS直接在模块对象上公开$provider方法,以节省更多的输入:

var myMod = angular.module('myModule', []);

myMod.provider("greeting", ...);
myMod.factory("greeting", ...);
myMod.value("greeting", ...);

这些都与我们以前使用的更详细的app.config(...)版本完全相同。

我迄今为止跳过的注射剂是constant 。 就目前而言,说起它就像value一样很容易。 我们会看到稍后有一个区别。

回顾一下,所有这些代码都是完全一样的:

myMod.provider('greeting', function() {
  this.$get = function() {
    return function(name) {
      alert("Hello, " + name);
    };
  };
});

myMod.factory('greeting', function() {
  return function(name) {
    alert("Hello, " + name);
  };
});

myMod.value('greeting', function(name) {
  alert("Hello, " + name);
});

注射器( $injector

注入器负责使用我们通过$provide (无双关语) $provide的代码实际创建我们服务的实例。 任何时候你写一个带注入参数的函数,你都会看到注入器在工作。 每个AngularJS应用程序都有一个$injector ,它在应用程序首次启动时创建; 你可以通过将$injector注入任何注入函数来获得它(是的, $injector知道如何注入它!)

一旦你有$injector ,你可以通过调用得到一个定义服务的实例get它的服务的名称。 例如,

var greeting = $injector.get('greeting');
greeting('Ford Prefect');

注入器还负责将服务注入功能; 例如,您可以将服务神奇地注入您使用注入器的invoke方法的任何函数中;

var myFunction = function(greeting) {
  greeting('Ford Prefect');
};
$injector.invoke(myFunction);

值得注意的是,注入器只会创建一次服务实例。 然后它通过服务的名称缓存提供者返回的任何内容; 下一次你要求服务时,你会得到完全相同的对象。

因此,要回答您的问题,可以将服务注入任何使用$injector.invoke调用的函数中 。 这包括

  • 控制器定义功能
  • 指令定义功能
  • 过滤器定义函数
  • 提供者的$get方法(又称factory定义函数)
  • 因为constant s和value s总是返回一个静态值,所以它们不会通过注入器被调用,因此你不能注入任何东西。

    配置提供者

    您可能想知道,为什么有人会在factoryvalue等方面比较容易地使用provide方法建立一个完整的提供商。 答案是提供商允许进行大量配置。 我们已经提到,当您通过提供者创建服务(或者Angular提供的任何捷径)时,您将创建一个新的提供者来定义该服务的构建方式。 我没有提到的是,这些提供程序可以注入到应用程序的config部分,以便您可以与它们交互!

    首先,Angular分两个阶段运行应用程序 - config阶段和run阶段。 正如我们所看到的, config阶段是您可以根据需要设置任何提供程序的地方。 这也是设置指令,控制器,过滤器等的地方。 您可能会猜到, run阶段是Angular实际编译您的DOM并启动您的应用程序的地方。

    您可以使用myMod.configmyMod.run函数添加额外的代码以在这些阶段运行 - 每个函数都会在该特定阶段运行一个函数。 正如我们在第一部分看到的,这些函数是可注入的 - 我们在第一个代码示例中注入了内置的$provide服务。 然而,值得注意的是, config阶段,只有提供者可以被注入 (除了AUTO模块中的服务 - $provide$injector )。

    例如,以下是不允许的

    myMod.config(function(greeting) {
      // WON'T WORK -- greeting is an *instance* of a service.
      // Only providers for services can be injected in config blocks.
    });
    

    您有权访问的是您所提供服务的任何提供商:

    myMod.config(function(greetingProvider) {
      // a-ok!
    });
    

    有一个重要的例外: constant s,因为它们不能被改变,允许被注入到config块内(这是它们与value s的不同之处)。 他们只能通过他们的名字访问(不需要Provider后缀)。

    无论何时为服务定义提供者,该提供者都将命名为serviceProvider ,其中serviceservice的名称。 现在我们可以利用提供商的力量做一些更复杂的事情!

    myMod.provider('greeting', function() {
      var text = 'Hello, ';
    
      this.setText = function(value) {
        text = value;
      };
    
      this.$get = function() {
        return function(name) {
          alert(text + name);
        };
      };
    });
    
    myMod.config(function(greetingProvider) {
      greetingProvider.setText("Howdy there, ");
    });
    
    myMod.run(function(greeting) {
      greeting('Ford Prefect');
    });
    

    现在我们在我们的提供者上有一个名为setText的函数,我们可以使用它来定制我们的alert ; 我们可以在config块中访问此提供程序以调用此方法并自定义该服务。 当我们最终运行我们的应用程序时,我们可以获取greeting服务,并尝试查看我们的定制生效。

    由于这是一个更复杂的例子,下面是一个工作演示:http://jsfiddle.net/BinaryMuse/9GjYg/

    控制器( $controller

    控制器功能可以注入,但控制器本身不能注入其他东西。 这是因为控制器不是通过提供者创建的。 相反,有一个名为$controller的内置Angular服务器负责设置您的控制器。 当您调用myMod.controller(...) ,您实际上正在访问此服务的提供者,就像在上一节中一样。

    例如,当你像这样定义一个控制器时:

    myMod.controller('MainController', function($scope) {
      // ...
    });
    

    你实际做的是这样的:

    myMod.config(function($controllerProvider) {
      $controllerProvider.register('MainController', function($scope) {
        // ...
      });
    });
    

    后来,当Angular需要创建你的控制器的一个实例时,它使用$controller服务(它反过来使用$injector来调用你的控制器函数,以便它也得到它的依赖注入)。

    过滤器和指令

    filterdirective工作方式与controller完全相同; filter使用名为$filter的服务及其提供者$filterProvider ,而directive使用名为$compile的服务及其提供者$compileProvider 。 一些链接:

  • $ filter:http://docs.angularjs.org/api/ng.$filter
  • $ filterProvider:http://docs.angularjs.org/api/ng.$filterProvider
  • $ compile:http://docs.angularjs.org/api/ng.$compile
  • $ compileProvider:http://docs.angularjs.org/api/ng.$compileProvider
  • 根据其他示例, myMod.filtermyMod.directive是配置这些服务的快捷方式。


    TL;博士

    因此,总而言之, 可以注入任何使用$injector.invoke调用的函数。 这包括从您的图表(但不限于):

  • 调节器
  • 指示
  • 过滤
  • 提供者$get (将提供者定义为对象时)
  • 提供者函数(将提供者定义为构造函数时)
  • 服务
  • 提供者创建可以注入事物的新服务。 这包括:

  • 不变
  • 提供商
  • 服务
  • 也就是说,可以注入像$controller$filter这样的内置服务,并且可以使用这些服务来获取您使用这些方法定义的新过滤器和控制器(即使您定义的内容本身不是,能够注入的东西)。

    除此之外,任何注入器调用的函数都可以注入任何提供者提供的服务 - 没有限制(除了此处列出的configrun差异)。


    BinaryMuse在关于提供商,工厂和服务的惊人答案中所做的一切都是非常重要的同一事物。

    下面是我认为可以直观地说明她的观点的图像:

    AngularJS他们都只是供应商http://www.simplygoodcode.com/wp-content/uploads/2015/11/angularjs-provider-service-factory-highlight.png


    Michelle很好的回答。 我只想指出, 指令可以被注入。 如果你有一个名为myThing的指令,你可以用myThingDirective注入它:这是一个人为的例子。

    上面的例子不是很实用,但是当你想修饰该指令时,注入指令的能力很有用。

    链接地址: http://www.djcxy.com/p/77789.html

    上一篇: What "things" can be injected into others in Angular.js?

    下一篇: What's the difference between the Dependency Injection and Service Locator patterns?