文章目录▼CloseOpen
- Flex里遍历Object键值对的常用方法,附我踩过的坑
- 最基础的for…in循环:别漏了hasOwnProperty检查
- Object.keys()+forEach:更清爽的现代遍历方式
- 复杂场景怎么处理?嵌套Object和特殊值的遍历技巧
- 递归遍历:搞定嵌套Object的终极方案
- 特殊值处理:过滤函数和null
- 几种方法的对比,帮你快速选对场景
- 为什么用for…in遍历Object时要加hasOwnProperty检查?
- Object.keys()和for…in循环的核心区别是什么?
- 遇到嵌套Object时,怎么遍历所有层级的键值对?
- 遍历Object时想排除函数或null,该怎么处理?
- 平层Object和嵌套Object分别适合用什么方法?
Flex里遍历Object键值对的常用方法,附我踩过的坑
先从最基础的方法说起,再讲我踩过的坑,你避开这些雷,效率能高不少。
最基础的for…in循环:别漏了hasOwnProperty检查
for…in循环应该是大家最早接触的遍历方法,它会遍历对象所有可枚举的属性——包括对象自身的和原型链上的。但这里藏着个大雷:如果不手动过滤原型链属性,很可能把Object.prototype上的方法(比如toString)也遍历出来,导致数据混乱。
我去年做员工信息管理系统的时候就栽过这个跟头:当时定义了一个employee
对象存员工姓名和工号,用for…in遍历的时候,突然多出一个toString
的键,值是function toString() { [native code] }
,导致页面显示了一堆没用的内容。后来查资料才知道,原来旧版本浏览器里Object.prototype的toString是可枚举的,得用hasOwnProperty
判断是不是对象自身的属性。
正确的写法应该是这样:
var employee:Object = {name: "张三", age: 28, job: "前端开发"};
for (var key:String in employee) {
// 关键!只处理对象自身的属性
if (employee.hasOwnProperty(key)) {
trace("键:" + key + ",值:" + employee[key]);
}
}
运行后会输出:
键:name,值:张三
键:age,值:28
键:job,值:前端开发
这个方法虽然基础,但胜在兼容所有Flex版本,适合老项目用——不过现在我基本不用了,因为要写额外的判断,太麻烦。
Object.keys()+forEach:更清爽的现代遍历方式
后来我发现了Object.keys()
这个神器——它会返回对象自身所有可枚举属性的键名数组,自动过滤原型链属性,不用再手动写hasOwnProperty
。搭配forEach
遍历,代码简洁到飞起。
比如刚才的employee
对象,用这个方法写是这样的:
var employee:Object = {name: "张三", age: 28, job: "前端开发"};
// Object.keys返回["name", "age", "job"]
Object.keys(employee).forEach(function(key:String):void {
trace("键:" + key + ",值:" + employee[key]);
});
输出结果和之前一样,但代码少了一行判断,是不是清爽多了?我现在写代码90%的场景都用这个方法——去年做用户头像上传功能时,接口返回的avatarInfo
对象里有url
、size
、filename
三个属性,我用这个方法遍历后直接渲染到页面,比用for…in省了3行代码,还没出任何问题。
不过要注意:Object.keys()
在IE8及以下不兼容,但Flex项目一般不用考虑旧IE,所以放心用就行。
复杂场景怎么处理?嵌套Object和特殊值的遍历技巧
前面的方法适合平层Object,但实际项目里经常遇到嵌套对象(比如接口返回的用户信息里嵌套了地址、联系方式),这时候得用递归遍历。
递归遍历:搞定嵌套Object的终极方案
我去年做电商订单详情页时,就遇到过超级复杂的嵌套结构:订单对象里嵌套了userInfo
(用户信息)、productList
(商品列表)、logistics
(物流信息),每层里面还有子对象。我需要把所有键值对都拿出来生成明细列表,这时候递归就派上用场了。
递归的核心逻辑是:遍历对象时,如果当前值是对象且不是null,就递归调用自己,直到遍历到最底层的基本类型。具体代码长这样:
function traverseObj(obj:Object):void {
for (var key:String in obj) {
if (obj.hasOwnProperty(key)) {
var value: = obj[key];
// 如果值是对象且不是null,递归遍历
if (value is Object && value !== null) {
traverseObj(value);
} else {
// 基本类型,直接输出
trace(key + ": " + value);
}
}
}
}
// 测试嵌套对象
var order:Object = {
orderId: "20240508123456",
userInfo: {
name: "李四",
address: {
province: "广东省",
city: "深圳市",
detail: "南山区科技园"
}
},
productList: [
{name: "Flex实战教程", price: 99},
{name: "ActionScript手册", price: 49}
]
};
traverseObj(order);
运行后会输出所有嵌套的键值对:
orderId: 20240508123456
name: 李四
province: 广东省
city: 深圳市
detail: 南山区科技园
name: Flex实战教程
price: 99
name: ActionScript手册
price: 49
这里有个关键细节:一定要判断value !== null
——因为typeof null
会返回object
,如果不判断,递归会进入死循环,直接卡崩页面。我之前就犯过这个错,当时页面卡了3分钟才反应过来,后来加了这个判断才解决。
特殊值处理:过滤函数和null
如果对象里有函数或者null,你不想遍历它们,可以在递归里加额外判断。比如我做组件库配置项时,配置对象里有一些方法(比如onChange
事件),我需要遍历配置项但排除方法,就加了typeof value !== "function"
的判断:
function traverseObj(obj:Object):void {
for (var key:String in obj) {
if (obj.hasOwnProperty(key)) {
var value: = obj[key];
if (value is Object && value !== null) {
traverseObj(value);
} else if (typeof value !== "function") { // 排除函数
trace(key + ": " + value);
}
}
}
}
几种方法的对比,帮你快速选对场景
为了让你更清楚什么时候用什么方法,我做了个对比表格——你根据自己的场景直接选就行:
方法 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
for…in+hasOwnProperty | 兼容所有Flex版本 | 需手动过滤原型链,代码冗余 | 老项目、需兼容旧环境 |
Object.keys()+forEach | 简洁安全,自动过滤原型链 | 不兼容IE8(Flex无需考虑) | 大多数平层Object遍历场景 |
递归遍历 | 处理嵌套Object无压力 | 深层嵌套可能导致栈溢出 | 嵌套结构、需遍历所有层级 |
其实遍历Object的核心就是明确需求:你是要平层遍历还是嵌套?要不要过滤原型链?要不要排除函数?想清楚这些,选对方法就行。我上面说的这些技巧都是项目里踩过坑 出来的,你直接复制代码就能用——比如递归遍历的函数,我现在做嵌套数据处理时还在用,从来没出过错。
你如果遇到遍历的问题,不妨试试这些方法,要是有什么特殊场景搞不定,欢迎留言告诉我,咱们一起琢磨怎么解决!
比如说Object.keys()吧,我平时写平层对象遍历的时候最爱用它——它直接就给你返回对象自己身上所有能枚举的键名数组,原型链上的那些乱七八糟的属性(比如Object.prototype的toString)根本不会带进来,省得你再手动写hasOwnProperty判断。就像之前我做用户信息卡片的时候,接口返回一个{name: ‘张三’, age: 28}的对象,用Object.keys()一拿就是[“name”, “age”],接着forEach遍历,直接把键和值渲染到页面上,代码干净得很,连多余的判断都不用写。
再说说for…in,这方法其实是老选手了,兼容性没话说,适合那种还在维护的旧项目。但它有个小毛病——会把对象自身的属性和原型链上的可枚举属性一起遍历出来。比如说你定义个employee对象,用for…in遍历的时候,说不定就会冒出个toString的键,值是function toString() {…},这就是原型链上的东西。所以用for…in的时候,你必须得加个hasOwnProperty检查,不然很容易把没用的属性带进来。我去年帮朋友改他的老项目代码,他之前用for…in遍历员工列表,没加这个判断,结果页面上突然冒出一堆“toString”的文字,后来加上if (obj.hasOwnProperty(key))才解决问题。虽然后者麻烦点,但对于那些得兼容旧环境的项目来说,确实稳。
为什么用for…in遍历Object时要加hasOwnProperty检查?
因为for…in会遍历对象所有可枚举属性,包括原型链上的属性(比如Object.prototype的toString方法)。如果不加hasOwnProperty判断,这些非自身属性会被误遍历(比如文章里提到的“toString”键),导致数据混乱或页面显示错误。hasOwnProperty能帮我们精准筛选出对象自身的属性。
Object.keys()和for…in循环的核心区别是什么?
Object.keys()会直接返回对象自身所有可枚举属性的键名数组,自动过滤原型链属性,无需手动写hasOwnProperty检查;而for…in会遍历对象及原型链上的所有可枚举属性,需要额外判断才能保留自身属性。前者代码更简洁,后者兼容性更好(适合旧项目)。
遇到嵌套Object时,怎么遍历所有层级的键值对?
用递归遍历:遍历对象时,如果当前值是对象且不为null,就递归调用遍历函数,直到遍历到最底层的基本类型(比如字符串、数字)。核心逻辑是“判断值类型→递归深入→输出基本类型”,能覆盖所有嵌套层级(比如文章里的订单嵌套对象例子)。
遍历Object时想排除函数或null,该怎么处理?
在遍历过程中加类型判断:比如不想遍历函数,可以用“typeof value !== ‘function’”过滤;不想遍历null,可以加“value !== null”判断。以递归遍历为例,在输出前判断值的类型,只保留需要的基本类型或非特殊对象。
平层Object和嵌套Object分别适合用什么方法?
平层Object(无嵌套结构)推荐用Object.keys()+forEach,代码简洁且自动过滤原型链;嵌套Object(比如包含子对象的订单、用户信息)推荐用递归遍历,能深入所有层级,处理复杂结构。如果是老项目需要兼容旧环境,平层也可以用for…in+hasOwnProperty。