第2章 Angular核心概念与生命周期

本章侧重:组件、模块、模板、生命周期钩子、变更检测机制。面试中90%的Angular基础题来源于这五大概念,掌握它们之间的协作关系与高频追问路径,是拿到Offer的关键。
生命周期钩子回答框架图 生命周期钩子 核心挂钩时机 ngOnInit 初始化 ngOnChanges 输入变更 ngOnDestroy 清理 回答框架: 钩子顺序 → 注意事项 加分点: 对比父子组件钩子执行 追问方向: 变更检测与钩子关系 ✅ 先答时机 → 再答用途 → 最后说注意点

📌 面试问题:请说出Angular组件生命周期钩子的执行顺序,并举例说明ngOnChanges和ngOnInit的区别。

面试官考察点是否理解组件创建到销毁全过程;能否区分输入属性变更与初始化;是否关注父子组件钩子顺序。
回答框架① 列出核心钩子顺序(constructor → ngOnChanges → ngOnInit → ngDoCheck → ngAfterContentInit → ngAfterContentChecked → ngAfterViewInit → ngAfterViewChecked → ngOnDestroy)。② 强调ngOnChanges在每次输入属性变化时调用(包括首次),而ngOnInit仅在初始化时调用一次。③ 举例:父组件传@Input值,子组件ngOnChanges先于ngOnInit触发。
简短示例回答“顺序为constructor→ngOnChanges→ngOnInit→…→ngOnDestroy。ngOnChanges每次@Input变化时触发,首次也在ngOnInit之前。比如父组件传user对象,ngOnChanges拿到变更前后值,ngOnInit只执行一次数据初始化。”
可能追问父组件先执行钩子还是子组件?子组件ngOnInit时父组件的View是否已初始化?如何手动触发变更检测?
⚠ 避坑提醒不要在ngOnChanges里做耗时操作;不要依赖ngDoCheck做频繁变更检测;ngOnDestroy记得取消订阅。

📌 面试问题:什么是Angular模块(NgModule)?它与Standalone组件有什么区别?

面试官考察点是否理解模块化组织方式;是否关注Angular14+新特性;能否对比两种模式适用场景。
回答框架① NgModule是Angular应用的编译单元,通过declarations、imports、providers、bootstrap组织。② Standalone组件(Angular14+)可独立使用,无需模块,通过imports导入所需指令/管道。③ 对比:传统模块适合大型项目分层,Standalone适合小模块或微前端。
简短示例回答“NgModule将组件、指令、管道组织成特性模块。Standalone组件通过@Component中的imports直接引用,无需@NgModule包装。我近期项目使用Standalone组件+Lazy loading,减少模块嵌套,构建速度提升约30%。”
可能追问Standalone组件能否使用providers?如何路由加载?hybrid模式兼容性问题?
⚠ 避坑提醒不要混用模块和Standalone的导入方式;Standalone组件中如需使用服务,需在@Component的providers或路由中注入。

📌 面试问题:Angular变更检测机制是什么?如何优化变更检测性能?

面试官考察点是否理解Zone.js原理;能否说清默认策略与OnPush策略;是否具备实际优化经验。
回答框架① 变更检测由Zone.js打补丁的异步事件触发,Angular从根组件向下遍历组件树,检查绑定表达式是否变化。② 默认策略每次事件都检测;OnPush策略只在@Input引用变化或组件内事件触发时检测。③ 优化方法:使用OnPush、配合ChangeDetectorRef.detach/reattach、使用pipe+pure filter、避免在模板中调用复杂方法。
简短示例回答“Zone.js截获setTimeout、XHR等异步操作后触发检测。我曾在数据大屏项目中将所有展示组件改为OnPush,配合immutable数据更新,页面帧率从45fps提升到60fps。”
可能追问ChangeDetectorRef.markForCheck与detectChanges区别?如何实现局部检测?Zone.js零污染方案?
⚠ 避坑提醒使用OnPush时必须保证@Input对象不可变;不要直接修改数组/对象,应创建新引用;避免在ngDoCheck中手动触发检测导致死循环。
变更检测机制 · 面试追问路径 变更检测 Zone.js 如何工作? patch异步API→触发回调 Default vs OnPush? immutable + markForCheck detach/detectChanges @Pipe pure & impure 追问逻辑:原理 → 策略 → 手动控制 → 管道优化

🚀 项目案例:企业级CRM客户管理平台(重构)

项目名称企业级CRM客户管理平台(Angular 16重构)
业务背景原有jQuery单页应用维护成本高,交互卡顿。团队决定使用Angular 16 + Standalone组件进行渐进式重构,实现组件化、模块化、响应式数据流。
规模指标120+组件;30+路由模块;日均PV 80万;用户在线数2000+;重构后首次加载时间从6.2s降至2.3s。
技术栈Angular 16 (Standalone) · TypeScript · RxJS · NGRX · Angular Material · SCSS · Jest · Cypress
核心难点1) 大量实时客户状态变更导致变更检测频繁,页面掉帧;2) 旧代码遗留的深层次对象引用引发OnPush失效;3) 团队从jQuery转Angular,生命周期理解不统一。
面试高频追问你们是如何用OnPush优化变更检测的?immutable数据怎么保证?NGRX的selector如何配合OnPush?遇到OnPush不更新怎么排查?
可迁移回答话术“我们首先对纯展示组件统一设置OnPush,配合NGRX的createSelector纯函数保证引用不变;遇到更新问题使用ChangeDetectorRef.markForCheck在事件中手动标记。同时用开发者工具changelog分析哪些组件被不必要检测,逐步优化。最终用户交互响应速度提升了40%。”
💡 面试加分提示: 在回答生命周期和变更检测时,主动提及项目中使用OnPush优化真实性能问题,能瞬间体现工程经验。配合具体指标(如检测次数减少50%)更有效。
⚠️ 常见雷区: 1) 把ngOnChanges和ngOnInit混为一谈;2) 认为OnPush完全不检测(实际仍然检测引用变化);3) 在模块中同时使用不同策略未处理好跨模块依赖。