而是只在表中填入“是”和“否”而没有任何解释,我将进一步详细介绍。
[注意,在完成后添加:最终结果是……比我预期的要长得多。底部有一个tl; dr,但我希望这能为您提供参考。]
[此答案也已添加到AngularJS Wiki:了解依赖注入 ]
该$provide
服务负责告诉Angular如何创建新的可注射事物;这些东西叫做服务。服务由称为提供者的东西定义,这是您在使用时创建的$provide
。定义提供程序是通过服务上的provider
方法完成的$provide
,您可以$provide
通过请求将其注入到应用程序的config
功能中来获得服务。一个例子可能是这样的:
app.config(function($provide) {
$provide.provider('greeting', function() {
this.$get = function() {
return function(name) {
alert("Hello, " + name);
};
};
});
});
在这里,我们为服务定义了一个新的提供程序greeting
;我们可以将一个名为变量的变量greeting
注入任何可注入的函数中(例如控制器,稍后再介绍),Angular会调用提供者的$get
函数以返回该服务的新实例。在这种情况下,将要注入的东西是一个函数,该函数接受一个基于名称的name
参数和alert
一条消息。我们可以这样使用它:
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(...)
我们以前使用的更详细的版本具有相同的作用。
到目前为止我跳过的注射剂是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);
});
注入程序负责使用通过我们提供的代码实际创建我们的服务实例$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始终返回静态值,因此不会通过注入器调用它们,因此您无法注入任何东西。
配置提供者
你可能会奇怪为什么会有人费心去建立一个全面的供应商与provide
方法,如果factory
,value
等都是容易得多。答案是提供程序允许大量配置。我们已经提到过,当您通过提供程序(或Angular提供的任何快捷方式)创建服务时,您将创建一个新的提供程序,用于定义该服务的构造方式。我没有提到的是,可以将这些提供程序注入到config
应用程序的各个部分中,以便您与它们进行交互!
首先,Angular分两个阶段(config
和和两个阶段)运行您的应用程序run
。config
如我们所见,该阶段是您可以根据需要设置任何提供程序的阶段。这也是设置指令,控制器,过滤器等的地方。run
您可能会猜到,这个阶段就是Angular实际编译DOM并启动应用程序的地方。
您可以使用myMod.config
和myMod.run
函数添加要在这些阶段中运行的其他代码-每个代码都需要一个函数在该特定阶段中运行。正如我们在第一部分中看到的那样,这些函数是可注入的-我们$provide
在第一个代码示例中注入了内置服务。然而,值得一提的是,在config
阶段,只有供应商可以注射(与服务的除外AUTO
module-- $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
,其中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');
});
现在我们在提供程序上有一个函数setText
,可以用来自定义我们的函数alert
;我们可以在一个config
块中访问此提供程序以调用此方法并自定义服务。当我们最终运行我们的应用程序时,我们可以获取该greeting
服务,然后进行尝试以查看我们的自定义生效。
由于这是一个更复杂的示例,因此下面是一个有效的演示:http : //jsfiddle.net/BinaryMuse/9GjYg/
可以将控制器功能注入,但是不能将控制器本身注入其他东西。这是因为控制器不是通过提供程序创建的。而是有一个内置的Angular服务$controller
,该服务负责设置控制器。致电时myMod.controller(...)
,您实际上是在访问该服务的提供程序,就像上一节中一样。
例如,当您定义这样的控制器时:
myMod.controller('MainController', function($scope) {
// ...
});
您实际上正在做的是:
myMod.config(function($controllerProvider) {
$controllerProvider.register('MainController', function($scope) {
// ...
});
});
后来,当Angular需要创建控制器的实例时,它将使用该$controller
服务(该服务又使用$injector
调用您的控制器功能,从而也注入其依赖项)。
过滤器和指令
filter
和directive
完全一样地工作controller
; filter
使用称为$filter
及其提供者的服务$filterProvider
,而directive
使用称为$compile
及其提供者的服务$compileProvider
。一些链接:
按照其他的例子,myMod.filter
并myMod.directive
有快捷键配置这些服务。
因此,总而言之,$injector.invoke
可以使用调用任何函数。从您的图表中包括(但不限于):
- 控制者
- 指示
- 厂
- 过滤
- 提供者
$get
(将提供者定义为对象时)
- 提供程序功能(将提供程序定义为构造函数时)
- 服务
提供者创建可以注入到事物中的新服务。这包括:
也就是说,内置的服务(例如$controller
和$filter
可以被注入),并且您可以使用这些服务来获取使用这些方法定义的新过滤器和控制器(即使您定义的内容本身不能做到)注入东西)。
除此之外,任何注入程序调用的功能都可以注入任何提供商提供的服务-没有限制(除了此处列出的config
和之间的run
差异)。