[Angular] 'providedIn' for service

There is now a new, recommended, way to register a provider, directly inside the @Injectable() decorator, using the new providedIn attribute. 

@Injectable({
  providedIn: 'root'
})
export class UserService {

}

 

When you use 'root', your injectable will be registered as a singleton in the application, and you don’t need to add it to the providers of the root module. Similarly, if you use providedIn: UsersModule, the injectable is registered as a provider of the UsersModule without adding it to the providers of the module.

 

In the same spirit, you can now declare an InjectionToken and directly register it with providedIn and give it a factory:

 export const baseUrl = new InjectionToken<string>('baseUrl', {
    providedIn: 'root',
    factory: () => 'http://localhost:8080/'
 });

 

Note that it also simplifies unit testing. We used to register the service in the providers of the testing module to be able to test it.

Before:

beforeEach(() => TestBed.configureTestingModule({
  providers: [UserService]
}));

Now, if the UserService uses providedIn: 'root':

After:

beforeEach(() => TestBed.configureTestingModule({}));

 

Angular 面试中,常见的问题通常围绕核心概念、框架机制、性能优化以及与其他前端技术的对比展开。以下是一些典型的 Angular 面试题及其详细解析: ### 什么是 Angular 的模块(NgModule)?它的作用是什么? Angular 模块是一个带有 `@NgModule` 装饰器的类,用于组织与应用程序相关的组件、指令、管道和服务。每个 Angular 应用至少包含一个根模块(通常命名为 `AppModule`),它可以导入其他功能模块、声明组件,并提供服务依赖注入。模块的作用是封装逻辑单元,便于管理和复用代码[^1]。 ### 解释 Angular 中的变化检测(Change Detection)机制 Angular 的变化检测是一种自动同步视图和模型状态的机制。它通过检查组件属性值是否发生变化来决定是否需要更新 DOM。默认情况下,Angular 使用“脏值检查”策略:每当事件触发(如用户交互、HTTP 请求完成等),变化检测会从根组件开始向下递归检查所有组件的状态。如果发现绑定属性的值发生变化,则更新对应的视图部分。 为了提高性能,可以使用 `OnPush` 变化检测策略。该策略仅当输入属性(`@Input()`)引用发生变化或显式调用 `markForCheck()` 方法时才会触发变化检测,从而减少不必要的检查次数。 ### 如何在 Angular 中实现依赖注入(Dependency Injection)? Angular 提供了一个强大的依赖注入系统,允许将服务或其他对象实例注入到组件、指令或管道中。可以通过构造函数注入的方式实现依赖注入。例如: ```typescript @Injectable({ providedIn: 'root' }) export class DataService { getData() { return of(['item1', 'item2']); } } @Component({ selector: 'app-example', templateUrl: './example.component.html' }) export class ExampleComponent { constructor(private dataService: DataService) {} } ``` 上述代码中,`DataService` 是一个可注入的服务,并通过 `providedIn: 'root'` 在根注入器中注册。`ExampleComponent` 通过构造函数注入了该服务的实例,以便在组件中使用。 ### Angular 中的生命周期钩子有哪些?请简要说明它们的作用 Angular 组件具有一系列生命周期钩子方法,开发者可以在特定阶段执行自定义逻辑。主要的生命周期钩子包括: - `ngOnChanges`: 当组件的输入属性 (`@Input`) 发生变化时调用。 - `ngOnInit`: 在组件初始化之后调用一次,常用于数据获取和初始化操作。 - `ngDoCheck`: 自定义变更检测逻辑。 - `ngAfterContentInit`: 在组件内容投影完成后调用。 - `ngAfterViewInit`: 在组件视图及其子视图初始化完成后调用。 - `ngOnDestroy`: 在组件销毁前调用,用于清理资源(如取消订阅、清除定时器)等[^1]。 ### Angular 中如何处理表单?有哪些类型的表单? Angular 支持两种主要的表单处理方式: 1. **模板驱动表单(Template-driven forms)**:适用于简单的表单场景,主要通过指令(如 `ngModel`)在模板中定义表单控件。验证规则也通过 HTML5 属性(如 `required`, `minlength`)进行配置。 2. **响应式表单(Reactive forms)**:适用于复杂的动态表单,基于 `FormControl`、`FormGroup` 和 `FormArray` 构建,具有更强的灵活性和可测试性。响应式表单的数据模型是不可变的,每次更改都会返回一个新的状态,因此更易于调试和管理。 ### Angular 中的服务(Service)和组件(Component)之间有什么区别? 组件的主要职责是管理视图和用户交互,而服务则用于封装业务逻辑、数据访问和共享功能。组件通常不会直接处理 HTTP 请求或复杂的数据操作,而是通过依赖注入调用服务中的方法。这种分离有助于保持组件的轻量性和可测试性,同时提升代码的复用性。 ### 如何在 Angular 中进行 HTTP 请求? Angular 提供了 `HttpClient` 模块用于发送 HTTP 请求。它基于 RxJS,支持诸如 `get`, `post`, `put`, `delete` 等方法,并返回可观测对象(Observable)。示例代码如下: ```typescript import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class ApiService { private apiUrl = 'https://api.example.com/data'; constructor(private http: HttpClient) {} getData() { return this.http.get(this.apiUrl); } } ``` 在组件中注入 `ApiService` 并调用其方法即可获取数据。此外,还可以通过拦截器(Interceptor)对请求和响应进行统一处理,例如添加认证头、日志记录等。 ### Angular 中的路由(Routing)是如何工作的? Angular 的路由器模块(`RouterModule`)提供了客户端路由功能,允许在单页应用中导航不同的视图。基本步骤包括: 1. 定义路由配置数组,指定路径和对应的组件; 2. 将路由模块注册到主模块中; 3. 使用 `<router-outlet>` 标签作为视图的占位符; 4. 使用 `Router` 服务进行编程式导航。 示例路由配置如下: ```typescript const routes: Routes = [ { path: 'home', component: HomeComponent }, { path: 'about', component: AboutComponent }, { path: '', redirectTo: '/home', pathMatch: 'full' } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule {} ``` 通过这种方式,用户可以在不同页面间切换而无需重新加载整个页面。 ### Angular 中的管道(Pipe)是什么?如何创建自定义管道? 管道用于在模板中转换数据格式,例如日期格式化、货币转换等。Angular 提供了一些内置管道(如 `date`, `currency`, `uppercase`),同时也支持创建自定义管道。要创建自定义管道,需使用 `@Pipe` 装饰器并实现 `transform` 方法: ```typescript @Pipe({ name: 'customFormat' }) export class CustomFormatPipe implements PipeTransform { transform(value: string, prefix: string): string { return `${prefix}-${value}`; } } ``` 然后在模块中声明该管道,并在模板中使用: ```html <p>{{ 'hello' | customFormat:'msg' }}</p> <!-- 输出:msg-hello --> ``` 自定义管道可以接受多个参数,并且可以设置纯/非纯模式(pure/impure),影响其重计算频率[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值