每个 Angular 开发者都熟悉的问题
\n\n您是否曾经尝试在 Angular 模板中使用 *ngFor 输出普通 JavaScript 对象的内容,然后突然意识到:"我该如何同时获取键和值?" 因为 *ngFor 默认只适用于数组。而对象不是数组。
这个问题是 Stack Overflow 上最热门的问题之一(数千次浏览和数十个答案)。开发者寻找的不仅仅是解决方案,而是正确的解决方案——一个不会影响应用程序性能的解决方案,尤其是当对象很大或频繁更新时。
\n\n在本文中,我们不仅会给出答案。我们将分析所有主要方法,从简单到高级,并展示如何编写快速且稳定运行的代码。让我们开始吧!
\n\n为什么 *ngFor 不能"开箱即用"地处理对象?
\n\nAngular 中的 *ngFor 指令是为可迭代结构(Iterable)设计的。数组是可迭代结构。对象不是。当您编写:
<div *ngFor="let item of myObject">{{ item }}</div>\n\nAngular 会报错:"Cannot find a differ supporting object '...'"。Angular 根本不知道如何遍历对象。
\n\n但在实践中,我们经常需要输出对象中的数据:配置、字典、API 响应,其中键具有意义(例如 { name: '安娜', age: 25, city: '莫斯科' })。
最简单的方法:Object.keys() 和 Object.entries()
\n\nStack Overflow 上最流行且最明显的答案是直接在模板中或组件中将对象转换为数组。
\n\n方法 1:Object.keys() —— 仅获取键
\n\n// 在组件中 (TypeScript)\nexport class MyComponent {\n myObject = { name: '安娜', age: 25, city: '莫斯科' };\n}\n\n<!-- 在模板中 -->\n<div *ngFor="let key of objectKeys(myObject)">\n 键: {{ key }}, 值: {{ myObject[key] }}\n</div>\n\n但这里有一个细节:objectKeys 必须在模板中可用。要么将其设为组件的方法,要么将其提取为单独属性:
// 组件\nexport class MyComponent {\n myObject = { name: '安娜', age: 25, city: '莫斯科' };\n objectKeys = Object.keys; // 只是原生函数的引用\n}\n\n这可行,但每次变更检测时都会调用该函数。如果对象很大,这会影响性能。
\n\n方法 2:Object.entries() —— 同时获取键和值
\n\n// 组件\nexport class MyComponent {\n myObject = { name: '安娜', age: 25, city: '莫斯科' };\n get entries() {\n return Object.entries(this.myObject);\n }\n}\n\n<!-- 模板 -->\n<div *ngFor="let entry of entries">\n 键: {{ entry[0] }}, 值: {{ entry[1] }}\n</div>\n\n或者使用解构(更易读):
\n\n<div *ngFor="let [key, value] of entries">\n 键: {{ key }}, 值: {{ value }}\n</div>\n\n优点:简单、清晰、直观。
\n缺点:entries 方法会在每次变更检测循环中被调用。对于静态对象可以接受,对于动态对象可能会成为问题。
性能:为什么这很重要?
\n\n想象一下,您的对象包含 10,000 条记录。或者它每 100 毫秒更新一次(例如,来自服务器的实时数据)。每次调用 Object.entries() 都会创建一个新数组。Angular 在每次变更检测循环中都会看到"新"数组,并重新渲染整个列表。这会导致界面抖动、输入框失去焦点以及卡顿。
因此,对于严肃的项目,需要使用优化