65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (10投票s)

2015 年 1 月 3 日

CPOL

7分钟阅读

viewsIcon

17968

获取 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 中这些难以理解的主题。我试图为您管理一个简单的例子。希望您喜欢它们。下篇文章再见,带来一个新主题。

© . All rights reserved.