Angular 面试题及详细答案
Angular 作为 Google 维护的企业级前端框架,其面试考察通常覆盖核心概念、生命周期、依赖注入、状态管理、性能优化等维度。以下整理了高频面试题及深度解析,帮助理解原理而非单纯记忆。
一、基础概念与核心特性
1. Angular 和 AngularJS 的主要区别是什么?
Angular(通常指 Angular 2+,简称 Angular)是 AngularJS(Angular 1.x)的完全重写版本,核心差异如下:
| 对比维度 | AngularJS (1.x) | Angular (2+) |
|---|---|---|
| 语言支持 | 仅支持 JavaScript | 推荐 TypeScript(强类型),也支持 JS |
| 架构模式 | MVC(Model-View-Controller) | 组件化架构(Component-Based) |
| 数据绑定 | 双向绑定(基于脏检查) | 双向绑定(基于 Zone.js)+ 单向绑定([]) |
| 依赖注入 | 模块级注入,配置复杂 | 层级注入(模块/组件/指令),API 更清晰 |
| 性能 | 脏检查机制,大应用性能差 | 增量变更检测,性能更优 |
| 移动支持 | 无原生支持,需第三方框架(如 Ionic 1) | 原生支持 PWA、移动端适配,可配合 Ionic 4+ |
| 生态 | 老旧,社区活跃度低 | 活跃,官方维护路由、表单等模块 |
2. Angular 的核心模块(Modules)有哪些?各自的作用是什么?
Angular 中模块(NgModule)是组织代码的基本单元,每个 Angular 应用至少有一个根模块(AppModule),核心模块分为:
| 模块名称 | 作用 |
|---|---|
BrowserModule |
浏览器平台必备模块,提供 ngIf、ngFor 等内置指令,仅根模块导入。 |
CommonModule |
包含 BrowserModule 的核心指令(无平台相关代码),子模块导入以复用指令。 |
FormsModule |
提供模板驱动表单支持(如 ngModel、ngForm)。 |
ReactiveFormsModule |
提供响应式表单支持(如 FormGroup、FormControl),更适合复杂表单。 |
RouterModule |
路由核心模块,通过 forRoot()(根模块)/forChild()(子模块)配置路由。 |
HttpClientModule |
提供 HTTP 请求能力(替代 AngularJS 的 $http),支持拦截器、TypeScript 类型。 |
3. 什么是 Angular 组件(Component)?它的核心组成部分有哪些?
组件是 Angular 应用的最小视图单元,负责封装 UI 结构、样式和逻辑,是“页面积木”。一个完整的组件由 4 部分组成:
-
装饰器(
@Component):定义组件元数据,核心属性包括:selector:组件的 HTML 标签名(如<app-user>),用于在其他模板中引用。template/templateUrl:组件的 HTML 模板(内联模板/外部文件路径)。styles/styleUrls:组件的 CSS 样式(内联样式/外部文件路径),默认样式隔离(仅作用于当前组件)。providers:在组件层级注入依赖(覆盖模块级注入)。
-
类(Class):包含组件的业务逻辑,如数据(
property)、方法(method),通过模板绑定与视图交互。 -
模板(Template):HTML 结构,通过 Angular 模板语法(如
{ {}}、[]、())绑定类中的数据和事件。 -
样式(Styles):组件的样式,支持
scoped(默认)、::ng-deep(穿透子组件样式)等特性。
示例:
// user.component.ts
import {
Component } from '@angular/core';
@Component({
selector: 'app-user',
template: `
<h2>Hello, {
{ userName }}!</h2>
<button (click)="changeName()">Change Name</button>
`,
styles: [`h2 { color: blue; }`]
})
export class UserComponent {
userName = 'Alice'; // 数据
changeName() {
// 方法
this.userName = 'Bob';
}
}
二、模板语法与数据绑定
1. Angular 有哪些数据绑定方式?分别用于什么场景?
Angular 提供 4 种核心绑定方式,覆盖“数据从类到视图”“视图到类”“双向同步”的场景:
| 绑定类型 | 语法示例 | 方向 | 作用场景 |
|---|---|---|---|
| 插值绑定 | {
{ user.name }} |
类 → 视图 | 展示类中的数据(文本内容)。 |
| 属性绑定 | <img [src]="imgUrl"> |
类 → 视图 | 绑定 HTML 属性/组件输入属性(如 [disabled])。 |
| 事件绑定 | <button (click)="onClick()"> |
视图 → 类 | 监听 DOM 事件/组件输出事件(如点击、输入)。 |
| 双向绑定 | <input [(ngModel)]="user.name"> |
类 ↔ 视图 | 数据在类和视图间同步(需导入 FormsModule)。 |
注意:双向绑定本质是“属性绑定 + 事件绑定”的语法糖,等价于 <input [value]="user.name" (input)="user.name = $event.target.value">。
2. 什么是 *ngIf 和 *ngFor?它们的区别和注意事项是什么?
两者都是 Angular 内置结构型指令(前缀 * 表示“修改 DOM 结构”):
*ngIf:条件渲染
- 作用:根据表达式布尔值决定是否在 DOM 中添加/移除元素(而非隐藏)。
- 示例:
<div *ngIf="isShow">仅当 isShow 为 true 时显示</div> - 注意:频繁切换可能触发 DOM 频繁创建/销毁,性能敏感场景可考虑
[hidden](仅隐藏,DOM 保留)。
*ngFor:循环渲染
- 作用:根据数组/可迭代对象生成重复的 DOM 元素。
- 核心语法:
*ngFor="let item of list; let i = index; trackBy: trackByFn" - 注意事项:
- 必须加
trackBy:默认情况下,数组变化时*ngFor会重新渲染所有元素;trackBy通过唯一标识(如id)复用 DOM,提升性能。 index变量:获取当前循环的索引(从 0 开始)。
- 必须加
trackBy 示例:
// 组件类
trackByUserId(index: number, user: User): number {
return user.id; // 用用户唯一 ID 跟踪
}
// 模板
<div *ngFor="let user of userList; trackBy: trackByUserId">
{
{
user.name }}
</div>
3. 什么是管道(Pipe)?常用的内置管道有哪些?
管道是 Angular 中用于转换模板数据格式的工具(如日期、货币、大小写转换),语法为 {
{ 数据 | 管道名: 参数 }}。
常用内置管道:
date:格式化日期,示例:{ { today | date: 'yyyy-MM-dd HH:mm' }}(输出:2024-05-20 14:30)。currency:格式化货币,示例:{ { price | currency: 'CNY' }}(输出:¥100.00)。uppercase/lowercase:转换大小写,示例:{ { 'hello' | uppercase }}(输出:HELLO)。async:处理异步数据(如Observable、Promise),自动订阅/取消订阅,避免内存泄漏,示例:{ { user$ | async }}。json:将对象转为 JSON 字符串,用于调试,示例:{ { user | json }}。
自定义管道:
通过 @Pipe 装饰器定义,需实现 PipeTransform 接口的 transform 方法。示例(首字母大写管道):
import {
Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'firstUpper' }) // 管道名称
export class FirstUpperPipe implements PipeTransform {
transform(value: string): string {
if (!value) return '';
return value[0].toUpperCase() + value.slice(1);
}
}
// 模板使用:{
{ 'angular' | firstUpper }} → 输出 Angular
三、组件通信
1. 父组件如何向子组件传递数据?
通过输入属性(@Input()) 实现,步骤如下:
-
子组件中用
@Input()装饰器定义可接收的属性:// 子组件:child.component.ts import { Input } from '@angular/core'; export class ChildComponent { @Input() childName: string; // 父组件可传递的属性 @Input('alias') age: number; // 可选:设置别名,父组件用别名传递 } -
父组件模板中通过属性绑定传递数据:

最低0.47元/天 解锁文章
1318

被折叠的 条评论
为什么被折叠?



