使用 Angular.js Providers 让您的编程生活更轻松!






4.94/5 (10投票s)
获取 Angular.js Providers 的清晰定义。了解其结构和基本区别。
引言
如果您正在疯狂使用 Angular.js,那么您可能知道可以在控制器中实现业务逻辑,并通过调用它们在应用程序的不同部分使用它们。但正如我们所知,在一个地方编写过多的代码从来都不是一个好主意。而且,不将大量的业务逻辑写入控制器被认为是一个好习惯,因为您可能需要在另一个控制器中再次使用相同的逻辑。因此,一遍又一遍地做同样的事情是多余的,而且容易出错。
背景
因此,在本文中,我将向您展示 Angular.js Providers 如何通过将这些业务逻辑从控制器中分离出来,并防止在应用程序中注入错误,从而使您的编程生命周期更轻松。
入门
那么,让我们从在 JavaScript 中创建一个简单的对象开始。在 JavaScript 中创建对象的方法有很多,但我将向您展示最简单、最受认可的方法。这被称为通过对象字面量创建对象。首先,我想创建一个 `arnoldSchwarzenegger`(一位好莱坞演员)对象。该对象将有一个属性用于存储演员的名字,一个属性用于姓氏,一个属性用于口头禅,最后还有一个属性,它将用所有这些先前的属性创建一个 `string` 并将其显示给应用程序用户。
Using the Code
创建对象字面量非常简单。它只是一些键值对。您所要做的就是定义一个键[一个表示属性名称的 `string`]和一个与其关联的值。因此,根据这个概念,我们的 `Arnold Schwarzenegger` 对象字面量将如下所示
var arnoldSchwarzenegger = {
firstName: "Arnold",
lastName: "Schwarzenegger",
catchPhrase: "Hasta la vista, baby",
sayCatchPhrase: function () {
return this.firstName + " " + this.lastName + " says " + this.catchPhrase;
}
};
现在,如果您像这样调用 `sayCatchPhrase` 属性
arnoldSchwarzenegger.sayCatchPhrase();
您将获得下面给出的 `string`。
"`阿诺德·施瓦辛格说:Hasta la vista, baby`"
记住在调用 `sayCatchPhrase` 时添加这些括号。由于 JavaScript 没有对象的方法,您可以通过在属性中封装一个函数来绕过此规则。
现在是时候创建 `clintEastwood` 对象了。一切都和以前一样。
var clintEastwood = {
firstName: "Clint",
lastName: "Eastwood",
catchPhrase: "Go ahead. Make my day",
sayCatchPhrase: function () {
return this.firstName + " " + this.lastName + " says " + this.catchPhrase;
}
};
clintEastwood.sayCatchPhrase();
“`克林特·伊斯特伍德说:Go ahead. Make my day`”
工厂模式
现在我们再创建一个。等一下!你可能会问自己,我为什么一遍又一遍地做同样的事情。为什么我不直接定义一个类并在该类中声明这些属性呢?然后,当需要时,我只需实例化该类的一个对象并使用这些属性。嗯,你说的对,我们确实在一遍又一遍地做同样的事情,但幸运的是,JavaScript 中没有类的概念。
但别担心,有志者事竟成。函数在 JavaScript 语言中就像一等公民。我们可以用函数做几乎任何事情。我们还可以在函数中创建对象并返回该对象。像这样的函数称为工厂函数。
因此,使用工厂函数创建并返回 `actor` 对象如下所示
var actor = function (firstName, lastName, catchPhrase) {
return {
firstName: firstName,
lastName: lastName,
catchPhrase: catchPhrase,
sayCatchPhrase: function () {
return this.firstName + " " + this.lastName + " says " + this.catchPhrase;
}
};
};
var clint = actor("Client", "Eastwood", "Go ahead. Make my day");
clint.sayCatchPhrase();
“`克林特·伊斯特伍德说:Go ahead. Make my day`”
我希望你喜欢我用工厂函数创建对象的方式,以避免重复做同样的事情。还有另一种创建对象的方式。
构造函数模式
好的,我已经向您展示了如何使用 JavaScript 工厂函数创建对象。到目前为止一切顺利。现在让我向您展示另一种在 JavaScript 中创建对象的方法。此方法包括使用构造函数创建对象。遵循此模式,您将像下面这样创建对象
var Actor = function (firstName, lastName, catchPhrase) {
this.firstName = firstName;
this.lastName = lastName;
this.catchPhrase = catchPhrase;
this.sayCatchPhrase = function() {
return this.firstName + " " + this.lastName + " says " + this.catchPhrase;
};
}
var clint = new Actor("Client", "Eastwood", "Go ahead. Make my day");
除了细微的变化,一切都和以前几乎一样。如您所见,当我们使用构造函数创建对象时,我们总是将变量(构造函数持有其引用的变量)的首字母大写。我们还使用了...
this
...然后是对象的属性名。在这里,我们不是使用冒号 ( : ) 将属性值分配给传入的参数之一,而是简单地使用等号 ( = ) 进行分配。最后但同样重要的是,我们通过创建它的新实例来调用该构造函数。
clint.sayCatchPhrase();
输出与之前相同
“`克林特·伊斯特伍德说:Go ahead. Make my day`”
那么,这两种创建 JavaScript 对象的模式之间有什么主要区别呢?如果我们用构造函数创建对象,那么该对象就带有一个类型。这意味着我们的 `clint` 是 `Actor` 类型。您可以通过简单地在浏览器的开发者控制台中写入...
clint instanceof Actor
...这将返回 `true`。但用工厂函数创建的对象没有类型。此外,当频繁创建特定类型的对象时,您会使用构造函数模式。
Angular.js Providers
最后,我们准备好讨论 Angular.js 提供了。确切地说,有五种类型的提供了,您可以通过它们在整个应用程序中提供了服务或信息作为数据(不要将服务与 Angular 自己的服务提供了混淆)。您所要做的就是定义一个服务类型一次,并在应用程序中的任何地方终身使用它。服务类型是
- Factory
- Service
- 提供商
- 值
- 恒定
对象是穿梭于应用程序不同部分并传递信息或服务的主要载体。Angular 服务提供商是以不同方式创建服务对象的方法。
Factory
列表中的第一个是工厂。顾名思义,它创建服务遵循工厂函数模式。我们在工厂模式一节中讨论了工厂函数作为创建对象的一种方式。
除了工厂函数之上的一些语法糖之外,这里没有什么新东西。因此,如果您的应用程序中定义了一个 Angular 模块,那么在该模块中使用工厂服务创建服务就像这样
var app = angular.module('app', []);
app.factory('movieFactory',function() {
return {
movies: [
{ title: "Die Hard", role: "Officer John McClane", released: "1988" },
{ title: "Unbreakable", role: "David Dunn", released: "2000" },
{ title: "The Sixth Sense", role: "Dr. Malcolm Crowe", released: "1999" },
{ title: "Armageddon", role: "Harry Stamper", released: "1998" },
{ title: "Twelve Monkeys", role: "James Cole", released: "1995" }
]
};
});
app.controller('movieController', function ($scope, movieFactory) {
$scope.movies = movieFactory.movies;
});
在上面,我有一个名为 `app` 的模块,我们在这个模块中声明了一个工厂服务提供商。我们还有一个控制器。在上面的例子中,我只是借助 Angular 工厂提供商创建了一个服务提供商。我们通过工厂暴露了一个电影服务。我们简单地创建了一个电影对象字面量数组并返回它。
现在,如果任何控制器想要使用我们的电影服务,它必须首先将 `movieFactory` 注入到控制器中[参见 `movieController` 函数参数]。然后,我们将从 `movieFactory` 的电影数组中获取的电影绑定到我们的 `$scope.movies` 模型中。就这样,如果我们按照以下方式编写 HTML,我们就可以开始了
<div ng-controller="movieController">
<h1><em>My Favourite Bruce Willis Movies</em></h1>
<div ng-repeat="movie in movies">
<div>{{movie.title}}</div>
<div>{{movie.role}}</div>
<div>{{movie.released}}</div>
<hr/>
</div>
</div>
我们将得到一个输出,例如
Service
因此,工厂服务提供商是暴露服务的一种好方法。但您可能不想使用工厂模式来暴露服务。相反,您可能希望利用构造函数模式作为创建服务的一种方式,这简单地称为服务。
如果你使用构造函数模式,你的服务提供商会是这样
var app = angular.module('app', []);
app.service('movieService',function() {
this.movies = [
{ title: "Die Hard", role: "Officer John McClane", released: "1988" },
{ title: "Unbreakable", role: "David Dunn", released: "2000" },
{ title: "The Sixth Sense", role: "Dr. Malcolm Crowe", released: "1999" },
{ title: "Armageddon", role: "Harry Stamper", released: "1998" },
{ title: "Twelve Monkeys", role: "James Cole", released: "1995" }
];
});
app.controller('movieController', function ($scope, movieService) {
$scope.movies = movieService.movies;
});
这只是语法糖
var app = angular.module('app', []);
function movieService() {
this.movies = [
{ title: "Die Hard", role: "Officer John McClane", released: "1988" },
{ title: "Unbreakable", role: "David Dunn", released: "2000" },
{ title: "The Sixth Sense", role: "Dr. Malcolm Crowe", released: "1999" },
{ title: "Armageddon", role: "Harry Stamper", released: "1998" },
{ title: "Twelve Monkeys", role: "James Cole", released: "1995" }
];
}
app.factory('movieFatory', function () {
return new movieService();
});
app.controller('movieController', function ($scope, movieFatory) {
$scope.movies = movieFatory.movies;
});
提供商
然后我们有一种创建服务的骨架方式,称为提供商(provider)。Angular 的提供商暴露了一个 `get` 函数,通过该函数我们可以获取我们服务的引用。使用提供商构建电影服务将如下所示
var app = angular.module('app', []);
function movieService() {
this.movies = [
{ title: "Die Hard", role: "Officer John McClane", released: "1988" },
{ title: "Unbreakable", role: "David Dunn", released: "2000" },
{ title: "The Sixth Sense", role: "Dr. Malcolm Crowe", released: "1999" },
{ title: "Armageddon", role: "Harry Stamper", released: "1998" },
{ title: "Twelve Monkeys", role: "James Cole", released: "1995" }
];
}
app.provider('movieProvider', function() {
this.$get = function getMovieService () {
return new movieService();
};
});
app.controller('movieController', function ($scope, movieProvider) {
$scope.movies = movieProvider.movies;
});
常量 & 值
最后,我们有了两个提供商。它们是 `value` 和 `constant` 提供商。它们几乎相同,只是常量一旦设置就不能更改,并且值不能注入任何配置中(我们稍后将讨论如何将常量注入 Angular 配置中)。
所以让我用这两个简单的例子来结束。要声明一个常量服务,我们将这样写
app.value('actorName', 'Bruce Willis');
app.controller('movieController', function ($scope, movieProvider, actorName) {
$scope.movies = movieProvider.movies;
$scope.actor = actorName;
});
在这里,我们创建了一个 `value` 服务提供商,它将在我们的控制器中提供一个演员名字,以便我们可以在视图中使用它,如下所示
<div ng-controller="movieController">
<h1><em>My Favourite {{actor}} Movies</em></h1>
<div ng-repeat="movie in movies">
<div>{{movie.title}}</div>
<div>{{movie.role}}</div>
<div>{{movie.released}}</div>
<hr/>
</div>
</div>
最后,我们可以像值提供商服务一样创建常量服务提供商
app.constant('actorName', 'Bruce Willis');
app.controller('movieController', function ($scope, movieProvider, actorName) {
$scope.movies = movieProvider.movies;
$scope.actor = actorName;
});
HTML 和值服务提供商中的 HTML 相同。稍后,我们将了解如何通过常量服务提供商在 Angular 应用程序中注入配置设置。
要点
我想现在您已经清楚了 Angular 中这些难以理解的主题。我试图为您管理一个简单的例子。希望您喜欢它们。下篇文章再见,带来一个新主题。