AngularJS 依赖注入 (Dependency Injection)

在 AngularJS 中,依赖注入(Dependency Injection,简称 DI) 是一种设计模式,它允许将所需的服务或对象“注入”到类的构造函数中,而不是让类自己去创建或查找它们。这使得代码更加模块化、易于测试和维护。

AngularJS 的依赖注入框架是其核心特性之一,它帮助你管理和自动化服务和组件之间的依赖关系。

1. 什么是依赖注入 (DI)

依赖注入是一种设计模式,通常用于松散耦合的系统中。它允许将对象的依赖关系从类的内部逻辑中解耦,通过外部传入这些依赖。

在 AngularJS 中,依赖注入主要是通过以下几种方式将服务、工厂、控制器等注入到应用中:

  • 控制器 (Controller)
  • 服务 (Service)
  • 工厂 (Factory)
  • 值 (Value)
  • 常量 (Constant)

2. AngularJS 中的依赖注入

AngularJS 会自动解析控制器、服务等所需的依赖,并将它们注入到相应的组件中。你可以将所需的依赖通过构造函数传递给控制器或服务。

2.1 控制器中的依赖注入

在 AngularJS 中,你可以通过依赖注入将服务、工厂等注入到控制器中。AngularJS 会自动将它们传递给控制器的构造函数。

var app = angular.module('myApp', []);

app.controller('MainController', function($scope, $http) {
    $scope.message = "Hello, AngularJS!";
    
    // 使用 $http 服务发送请求
    $http.get('https://jsonplaceholder.typicode.com/posts')
        .then(function(response) {
            $scope.posts = response.data;
        });
});

在这个例子中,$http 是一个 AngularJS 内置服务,$scope 是用于控制器与视图之间共享数据的对象。AngularJS 会自动注入这些依赖到控制器中。

2.2 服务和工厂的依赖注入

服务和工厂是 AngularJS 中用于共享业务逻辑和数据的组件,它们也可以通过依赖注入进行管理。

var app = angular.module('myApp', []);

app.service('greetingService', function() {
    this.greet = function(name) {
        return 'Hello, ' + name + '!';
    };
});

app.controller('MainController', function($scope, greetingService) {
    $scope.greeting = greetingService.greet('AngularJS');
});

在这个例子中,greetingService 是一个 AngularJS 服务,它有一个 greet 方法。这个服务通过依赖注入被传递到 MainController 控制器中。

2.3 通过 $inject 显式注入依赖

虽然 AngularJS 的依赖注入系统通常会通过函数参数名称来自动注入依赖,但有时你需要显式指定依赖。此时,你可以使用 $inject 属性。

var app = angular.module('myApp', []);

app.controller('MainController', ['$scope', '$http', function($scope, $http) {
    $scope.message = "Hello, AngularJS!";
    
    $http.get('https://jsonplaceholder.typicode.com/posts')
        .then(function(response) {
            $scope.posts = response.data;
        });
}]);

通过 $inject 明确注入依赖时,AngularJS 会根据传递的数组顺序自动注入服务。这样做可以避免压缩时由于参数名改变而导致依赖注入失败的问题。

3. AngularJS 服务的依赖注入

AngularJS 的服务(如 $http$route$scope)是使用依赖注入提供给控制器、指令或服务的。AngularJS 将服务实例化并将它们注入到需要的地方。

3.1 服务(Service)

AngularJS 服务是一种用于共享和重用业务逻辑的机制,可以在整个应用中被注入和复用。

var app = angular.module('myApp', []);

app.service('myService', function() {
    this.sayHello = function(name) {
        return 'Hello, ' + name;
    };
});

app.controller('MainController', function($scope, myService) {
    $scope.greeting = myService.sayHello('Angular');
});

在这个例子中,myService 服务提供了一个 sayHello 方法,MainController 控制器通过依赖注入将其注入,并使用该方法。

3.2 工厂(Factory)

与服务类似,工厂也是 AngularJS 中用于创建可复用对象的构造函数。工厂返回的是一个对象或函数,并且可以包含更多的逻辑。工厂的依赖注入工作方式与服务相同。

var app = angular.module('myApp', []);

app.factory('myFactory', function() {
    return {
        greet: function(name) {
            return 'Hello, ' + name;
        }
    };
});

app.controller('MainController', function($scope, myFactory) {
    $scope.greeting = myFactory.greet('Angular');
});

3.3 值和常量(Value & Constant)

值 (value) 和常量 (constant) 是用于存储简单数据的 AngularJS 服务。它们的区别在于常量是不可修改的。

var app = angular.module('myApp', []);

app.value('greetingValue', 'Hello, Angular!');
app.constant('greetingConstant', 'Hello, World!');

app.controller('MainController', function($scope, greetingValue, greetingConstant) {
    $scope.valueGreeting = greetingValue;
    $scope.constantGreeting = greetingConstant;
});

4. 依赖注入的优势

  • 松散耦合:组件之间的依赖关系被解耦,使得模块之间不需要直接引用其他模块。
  • 易于测试:由于依赖可以通过注入进行提供,因此更容易为单个组件编写单元测试,而不需要关注它们的创建和初始化过程。
  • 更好的模块化:依赖注入使得应用程序的组件更加独立,便于维护和扩展。
  • 自动管理依赖:AngularJS 会自动管理和注入依赖,减少了手动创建和管理依赖的复杂性。

5. 总结

  • 依赖注入(DI) 是 AngularJS 的核心特性之一,它使得应用程序组件之间的依赖关系更加松散,从而提升了代码的可维护性、可重用性和可测试性。
  • AngularJS 提供了多种注入方式,包括通过控制器、服务、工厂等组件注入依赖。
  • 通过使用依赖注入,AngularJS 可以轻松管理应用中的服务和其他依赖,自动化处理依赖的创建和生命周期。