查看: 179|回复: 0

JS空对象判断:Object.keys与JSON.stringify

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在JavaScript业务代码中,判断对象是否为空常用于参数校验、缓存命中和配置默认值处理。原文给出的首选是 Object.keys(obj).length === 0:它写法简洁,只检查自身可枚举属性,不受原型链影响,性能也较好。但使用前必须先确认 obj 不是 null 或 undefined,否则 Object.keys 会直接抛错。原文给出的健壮表达式是:
  1. var obj = null;
  2. var isEmpty = obj != null && Object.keys(obj).length === 0;
  3. console.log(isEmpty); // false
复制代码

常用方法及边界如下:
1. Object.keys(obj).length === 0:最常用,只统计自身可枚举属性,不包含Symbol键。
2. JSON.stringify(obj) === '{}':写法简单,但值为 undefined、函数或 Symbol 的属性会被忽略,可能误判;循环引用会直接报错。
3. for...in 配合 hasOwnProperty:for...in 能遍历到原型链上的可枚举属性,所以必须用 hasOwnProperty 过滤,代码稍繁琐。jQuery 的 $.isEmptyObject() 可视为对该思路的封装,但需要项目已引入 jQuery。
4. Object.getOwnPropertyNames(obj).length === 0:能检测不可枚举属性,比 Object.keys 更严格,但同样不包含 Symbol 键。
5. Reflect.ownKeys(obj).length === 0:最彻底,包含不可枚举属性和 Symbol 键,适合要求“绝对空”的场景,日常用得少。
6. 第三方库:如 lodash 的 _.isEmpty(obj),适合项目已引入该库的情况。

原文示例可直接对照:
  1. var data = {};
  2. var b1 = Object.keys(data).length === 0;
  3. console.log(b1); // true
  4. var b2 = JSON.stringify(data) === '{}';
  5. console.log(b2); // true
  6. var b3 = (function () {
  7.   for (var key in data) {
  8.     return false;
  9.   }
  10.   return true;
  11. })();
  12. console.log(b3); // true
  13. var b4 = Object.getOwnPropertyNames(data).length === 0;
  14. console.log(b4); // true
  15. var b5 = $.isEmptyObject(data);
  16. console.log(b5); // true
  17. var b6 = Reflect.ownKeys(data).length === 0;
  18. console.log(b6); // true
复制代码

关键注意点:判断前先排除 null 和 undefined;如果对象里可能只有 Symbol 属性,Object.keys、JSON.stringify、for...in 都会失效,只有 Reflect.ownKeys 能正确识别。原文的建议很明确:日常业务用 Object.keys 就够,追求严格空再用 Reflect.ownKeys,不必过度设计。

JSON.stringify 的语法为 JSON.stringify(value[, replacer[, space]])。value 是必需项,通常为对象或数组;replacer 可选,为函数时逐成员调用并用返回值替换原值,返回 undefined 会排除该成员,为数组时只转换数组中具有键值的成员;space 可选,用于缩进和换行,数字大于10时按10个空格处理,也可使用 \t 等非数字字符。返回值是包含 JSON 文本的字符串。原文列出的序列化特性,直接影响判空和深拷贝:

1. undefined、任意函数和 Symbol 作为对象属性值时会被跳过;作为数组元素值时会被序列化为 null;作为单独值序列化时返回 undefined。
  1. var data = {
  2.   a: 'aaa',
  3.   b: undefined,
  4.   c: Symbol('dd'),
  5.   fn: function () { return true; }
  6. };
  7. console.log(JSON.stringify(data)); // 输出结果只保留 a 属性
复制代码

2. 非数组对象的属性不能保证以特定顺序出现在序列化后的字符串中,数组除外。
3. 转换值如果有 toJSON() 函数,该函数返回什么值,序列化结果就是什么值,并忽略其他属性。
4. Date 值会被正常序列化。
5. NaN 和 Infinity 格式的数值及 null 都会被当做 null。
6. 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
7. 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。
8. 用 JSON.parse(JSON.stringify()) 做深拷贝时,循环引用会抛出错误。原文示例的错误类型为 TypeError: Converting circular structure to JSON。
  1. const obj = { name: 'loopObj' };
  2. const loopObj = { obj: obj };
  3. obj.loopObj = loopObj;
  4. function deepClone(value) {
  5.   return JSON.parse(JSON.stringify(value));
  6. }
  7. deepClone(obj);
  8. // TypeError: Converting circular structure to JSON
复制代码

综上,判空优先用 Object.keys 并先做空值保护;需要把不可枚举属性和 Symbol 键也纳入时,改用 Reflect.ownKeys。JSON.stringify 写法短,但因会忽略 undefined、函数和 Symbol 属性,还存在循环引用报错问题,不适合作为唯一判空依据。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-24 16:28 , Processed in 0.025369 second(s), 29 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部