面试题答案
一键面试Angular依赖注入基本原理
- 容器概念:Angular有一个依赖注入容器,它负责创建、管理和提供对象实例。这个容器就像一个仓库,存放着各种对象实例。
- 注册与解析:
- 注册:开发者需要在模块(NgModule)中使用
providers
数组将依赖(通常是服务)注册到依赖注入容器中。比如,有一个UserService
,可以这样注册:
- 注册:开发者需要在模块(NgModule)中使用
import { NgModule } from '@angular/core';
import { UserService } from './user.service';
@NgModule({
providers: [UserService]
})
export class AppModule {}
- 解析:当一个组件(或其他注入点,如服务本身)需要某个依赖时,Angular会在依赖注入容器中查找并解析该依赖。如果容器中没有该依赖的实例,它会根据注册的方式创建一个新的实例。例如,一个组件
UserComponent
依赖UserService
:
import { Component } from '@angular/core';
import { UserService } from './user.service';
@Component({
selector: 'app - user',
templateUrl: './user.component.html'
})
export class UserComponent {
constructor(private userService: UserService) {}
}
这里通过构造函数注入,Angular会从容器中获取UserService
的实例并注入到UserComponent
中。
实际项目中使用依赖注入管理组件间依赖关系示例
假设我们有一个电商项目,有一个CartComponent
用于显示购物车信息,它依赖于CartService
来获取购物车数据。
- 创建
CartService
:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class CartService {
private cartItems = [];
addItemToCart(item) {
this.cartItems.push(item);
}
getCartItems() {
return this.cartItems;
}
}
这里@Injectable({ providedIn: 'root' })
表示将CartService
注册到根注入器(全局可用)。
2. 使用CartService
的CartComponent
:
import { Component } from '@angular/core';
import { CartService } from './cart.service';
@Component({
selector: 'app - cart',
templateUrl: './cart.component.html'
})
export class CartComponent {
cartItems;
constructor(private cartService: CartService) {
this.cartItems = this.cartService.getCartItems();
}
}
通过依赖注入,CartComponent
可以轻松获取CartService
的功能,而无需手动创建CartService
实例,解耦了组件和服务之间的关系。
依赖注入带来的优势
- 可测试性提高:在测试
CartComponent
时,可以轻松地提供一个模拟的CartService
,而不是依赖真实的CartService
。例如:
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CartComponent } from './cart.component';
import { CartService } from './cart.service';
describe('CartComponent', () => {
let component: CartComponent;
let fixture: ComponentFixture<CartComponent>;
let mockCartService = {
getCartItems: () => []
};
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [CartComponent],
providers: [
{ provide: CartService, useValue: mockCartService }
]
});
fixture = TestBed.createComponent(CartComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
通过提供模拟的CartService
,可以独立测试CartComponent
,不受CartService
具体实现的影响。
2. 代码解耦:组件不需要关心依赖的创建和管理,只专注于使用依赖。比如CartComponent
只需要使用CartService
的功能,而不需要知道CartService
如何获取或存储购物车数据,使得组件和服务可以独立开发和维护。
3. 可维护性增强:如果CartService
的实现发生变化,比如从本地存储改为服务器端获取购物车数据,只需要修改CartService
本身,CartComponent
等依赖它的组件不需要修改,因为依赖注入的接口保持不变。