angularjs - 什么 "things"可以在 Angular.js 中注入(inject)其他人?

标签 angularjs dependency-injection

我很难理解 Angular 中的依赖注入(inject)。所以我的问题是,谁能解释哪些“类型”,如 Controller 、工厂、提供者等,我们可以注入(inject)其他人,包括相同“类型”的其他实例?

我真正要找的是这张填满 y/n 的表格。对于具有相同行/列的单元格,这意味着将一种“类型”的值注入(inject)另一种具有相同“类型”的值

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

最佳答案

与其在表格中填写"is"和“否”而不做任何解释,我将更详细地介绍一下。

[注意,完成后补充:这最终是……比我预期的要长得多。底部有一个 tl;dr,但我希望这能提供信息。]

[此答案也已添加到 AngularJS wiki:Understanding Dependency Injection ]

提供者 ( $provide )
$provide service 负责告诉 Angular 如何创建新的可注入(inject)的东西;这些东西叫做服务 .服务由名为 的东西定义。供应商 ,这就是您在使用 $provide 时创建的内容.定义提供者是通过 provider 完成的$provide上的方法服务,您可以得到$provide通过要求将服务注入(inject)应用程序的 config功能。一个例子可能是这样的:

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

在这里,我们为名为 greeting 的服务定义了一个新的提供者。 ;我们可以注入(inject)一个名为 greeting 的变量进入任何可注入(inject)的函数(如 Controller ,稍后会详细介绍),Angular 将调用提供者的 $get函数以返回服务的新实例。在这种情况下,将被注入(inject)的是一个函数,它接受一个 name参数和 alert s 基于名称的消息。我们可以这样使用它:

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

现在是诀窍。 factory , service , 和 value都只是定义提供者各个部分的快捷方式——也就是说,它们提供了一种定义提供者的方法,而无需输入所有内容。例如,您可以这样写 完全相同的提供商 就像这样:

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);
  });
});

同样,这与我们用来定义此函数的其他两种方法 100% 相同——这只是一种节省一些输入的方法。

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

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

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

这些都与更详细的 app.config(...) 做同样的事情我们以前使用的版本。

到目前为止我跳过的一个注入(inject)剂是 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);
});

注入(inject)器 ( $injector )

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

一旦您拥有 $injector ,您可以通过调用 get 获取已定义服务的实例。在它上面加上服务的名称。例如,

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

注入(inject)器还负责将服务注入(inject)到函数中;例如,您可以使用注入(inject)器的 invoke 神奇地将服务注入(inject)到您拥有的任何函数中。方法;

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

值得注意的是,注入(inject)器只会创建一次服务的实例。然后它缓存提供者按服务名称返回的任何内容;下次您请求服务时,您实际上会得到完全相同的对象。

因此,要回答您的问题,您可以将服务注入(inject) 任何用 $injector.invoke 调用的函数 .这包括
  • Controller 定义函数
  • 指令定义函数
  • 过滤器定义函数
  • $get提供者的方法(又名 factory 定义函数)

  • constant s 和 value s 总是返回一个静态值,它们不是通过注入(inject)器调用的,因此你不能用任何东西注入(inject)它们。

    配置提供者

    您可能想知道为什么有人会费心使用 provide 来建立一个成熟的提供商。方法如果 factory , value等就容易多了。答案是提供者允许大量配置。我们已经提到,当您通过提供者(或 Angular 为您提供的任何快捷方式)创建服务时,您将创建一个新的提供者,该提供者定义了该服务的构造方式。我没有提到的是这些提供者可以注入(inject)config应用程序的各个部分,以便您可以与它们进行交互!

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

    您可以使用 myMod.config 添加要在这些阶段运行的其他代码。和 myMod.run函数——每个函数都在特定阶段运行一个函数。正如我们在第一节中看到的,这些函数是可注入(inject)的——我们注入(inject)了内置的 $provide在我们的第一个代码示例中提供服务。然而,值得注意的是期间config阶段,只有提供者可以注入(inject) (除了 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!
    });
    

    有一个重要的异常(exception):constant s,因为它们不能被改变,所以被允许注入(inject)到config里面块(这就是它们与 value s 的不同之处)。它们仅通过名称访问(不需要 Provider 后缀)。

    每当您为服务定义提供者时,该提供者都会被命名为 serviceProvider ,其中 service是服务的名称。现在我们可以利用提供者的力量做一些更复杂的事情了!

    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');
    });
    

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

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

    Controller ( $controller )

    Controller 函数可以注入(inject),但 Controller 本身不能注入(inject)其他东西。那是因为 Controller 不是通过提供者创建的。相反,有一个名为 $controller 的内置 Angular 服务。负责设置您的 Controller 。当您拨打 myMod.controller(...) ,您实际上正在访问 this service's provider ,就像上一节一样。

    例如,当您像这样定义 Controller 时:

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

    你实际上在做什么是这样的:

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

    稍后,当 Angular 需要创建 Controller 的实例时,它会使用 $controller服务(反过来使用 $injector 来调用您的 Controller 函数,以便它也注入(inject)其依赖项)。

    过滤器和指令
    filterdirective工作方式与 controller 完全相同; filter使用名为 $filter 的服务及其提供者 $filterProvider , 而 directive使用名为 $compile 的服务及其提供者 $compileProvider .一些链接:
  • $过滤器:https://docs.angularjs.org/api/ng/service/$filter
  • $filterProvider: https://docs.angularjs.org/api/ng/provider/$filterProvider
  • $编译:https://docs.angularjs.org/api/ng/service/$compile
  • $compileProvider: https://docs.angularjs.org/api/ng/provider/$compileProvider

  • 根据其他示例,myMod.filtermyMod.directive是配置这些服务的快捷方式。

    tl;dr

    因此,总而言之,任何使用 $injector.invoke 调用的函数可以注入(inject) .这包括,从您的图表(但不限于):
  • Controller
  • 指令
  • 工厂
  • 过滤器
  • 供应商$get (当将提供者定义为对象时)
  • provider 函数(当将 provider 定义为构造函数时)
  • 服务

  • 提供者创建新服务 可以注入(inject)的东西 .这包括:
  • 常数
  • 工厂
  • 供应商
  • 服务
  • 值(value)

  • 也就是说,内置服务如 $controller$filter可以注入(inject),并且您可以使用这些服务来获取您使用这些方法定义的新过滤器和 Controller (即使您定义的事物本身不能注入(inject)事物)。

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

    关于angularjs - 什么 "things"可以在 Angular.js 中注入(inject)其他人?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16828287/

    相关文章:

    javascript - 将参数从 Angularjs 传递到 Django

    c# - Ninject -> 扫描程序集以匹配接口(interface)并加载为模块

    java - 我可以注入(inject)内部类的对象吗?

    javascript - 如何正确调用我的工厂服务?

    javascript - AngularJS 数据模型架构

    Angular : multiple promise wait all

    spring - 如何使用@Configuration排除spring配置文件以依赖其他项目

    c# - ASP.NET Core 使用依赖注入(inject)访问其他服务

    android - 尝试使用 Dagger2 和 Kotlin 将 ViewModelProvider 注入(inject) Activity 时出错

    javascript - Angularjs指令删除父div中的所有内容