JS判断对象为空:避开90%人的踩坑写法
JS里没有万能的空对象判断方法,不同写法适配不同场景,选错就会出现明明对象有内容,代码却判定为空的隐形bug。日常开发最稳妥的通用方案是组合判断,先规避null、undefined边界,再检测对象自身属性,你平时写的简单判断,真的能覆盖所有特殊情况吗?
很多新手入门都会踩一个低级坑,直接用if(!obj)判断空对象。
这完全行不通。
在JS的隐式转换规则里,空对象{}是真值,!obj的结果永远是false。哪怕你拿到一个看起来干干净净的空对象,这种判断方式从根上就失效,不管对象有没有属性,代码都会默认它有值,直接跳过空值校验。
最省事但有漏洞的两种常用写法
先说说大家用得最多、却暗藏隐患的两种方法,这也是我早年写项目时翻车的核心原因。
第一种是JSON序列化判断,也就是JSON.stringify(obj) === '{}'。
这个方法优点极度直观,一眼就能看懂,不用记复杂API,适合新手快速上手。但它的缺陷特别致命,容错率极低。它会直接忽略对象里的undefined、函数、Symbol类型属性,哪怕对象挂载了这些属性,序列化后依然会变成{}。之前做表单提交校验时,一个用户信息对象藏了一个undefined的备用字段,用这个方法判空直接通过,导致后端接收空字段报错,线上直接弹出30多条异常日志。
第二种是for...in循环遍历判断。
原理很简单,遍历对象属性,能遍历到属性就判定非空,遍历不到就是空对象。但它最大的问题是会遍历原型链上的继承属性,而且识别不了不可枚举属性。如果项目里有人修改了Object原型,这个判断就会彻底失灵,误把有原型属性的对象判定为非空。
日常开发的最优通用方案
绝大多数业务场景,优先用Object.keys(),这是兼顾简洁、准确、性能的最优解。
它的逻辑很纯粹,只获取对象自身的可枚举属性,完全不触碰原型链,规避了for...in的原型污染问题。写法也极简,判断Object.keys(obj).length === 0即可,数组长度为0,就代表对象没有任何自有可枚举属性,是纯正的空对象。
但它也不是完美的,依然有两个盲区。识别不了不可枚举属性,也识别不了Symbol类型的键名。如果你的业务场景会用到这两种特殊属性,单纯的Object.keys()就不够精准。
极致精准的全场景判断方案
想要覆盖所有特殊情况,做到零误判,就需要组合API实现完整校验,适配所有复杂对象。
- 先用obj == null过滤掉null和undefined,这两个严格来说不属于对象,不提前拦截会直接报错中断代码
- 用Object.getOwnPropertySymbols()检测所有Symbol类型键
- 用Object.getOwnPropertyNames()捕获不可枚举属性
三者结合,就能把对象所有自有属性,不管类型、不管是否可枚举,全部检测到位,彻底杜绝漏判问题。这个方案唯一缺点是代码稍长,但稳定性拉满,适配后台管理系统、数据校验等严谨场景。
很多人分不清场景,一律用最简单的写法,才频繁出现隐性bug。
简单总结一下取舍逻辑:普通业务对象校验,直接用Object.keys()足够高效;涉及特殊属性、严谨数据校验,用全量组合判断;JSON序列化、for...in只适合临时简单调试,绝不用于线上正式代码。
写通用工具函数时,直接封装这套分层判断,就能一劳永逸解决空对象判断的所有问题。