JS里怎么判断一个对象是否为空?怎么分清它到底是啥类型?

739 阅读3分钟

对象{},它明明看着是空的,但JS说它“不是假值”,if ({})还是成立的。这就尴尬了。

到底怎么才算“空对象”?又怎么知道一个东西到底是对象、数组、还是别的啥?

一、怎么判断一个对象是否为空?

先说结论:一个“空对象”通常是指它没有任何可枚举的自有属性

比如:

const obj1 = {};
const obj2 = { name: '张三' };

obj1是空的,obj2不是。

方法1:Object.keys()

这是我现在最常用的方法。

function isEmpty(obj) {
  return Object.keys(obj).length === 0;
}

isEmpty({}); // true
isEmpty({ name: '张三' }); // false

使用场景:我之前做后台管理系统,有个接口返回用户配置:

const config = await fetchConfig();
if (isEmpty(config)) {
  alert('请先设置你的偏好');
}

这个方法简单直接,而且只看对象自己的属性,不看原型链,很安全。

注意:它只适用于普通对象。比如数组、函数这些,也可以用Object.keys()。但数组更自然的判断是arr.length === 0

方法2:for...in遍历

老派但可靠的方法:

function isEmpty(obj) {
  for (let key in obj) {
    return false; // 只要能进循环,说明有属性
  }
  return true;
}

这个方法也行,但要小心原型链上的属性。比如:

const obj = {};
obj.__proto__.abc = 'xxx'; // 别这么干,只是举例

这时候for...in会遍历到abc,但Object.keys()不会。

所以如果你不确定对象有没有被“污染”原型,建议配合 hasOwnProperty

function isEmpty(obj) {
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      return false;
    }
  }
  return true;
}

不过现在大家一般不乱改原型了,所以 Object.keys 更省心。

方法3:JSON.stringify()

有人这么写:

JSON.stringify(obj) === '{}'

这方法能用,但有坑:

  • 如果对象里有undefined、函数、Symbol,会被忽略,结果可能不准。
  • 性能差一点,毕竟要序列化。

所以我不推荐,除非你特别确定数据结构。

二、怎么区分数据类型?

JS的类型判断一直是个“玄学”。比如:

typeof []      // "object"
typeof null    // "object"

这就很离谱。所以我们得用别的办法。

1. 判断是不是数组

别再用typeof了,用Array.isArray()

Array.isArray([])     // true
Array.isArray({})     // false

使用场景:我之前写一个数据处理函数,接收的参数可能是单个对象,也可能是对象数组:

function handleData(data) {
  const list = Array.isArray(data) ? data : [data];
  list.forEach(item => console.log(item));
}

handleData({name: '张三'});        // 包装成数组
handleData([{name: '张三'}]);      // 直接用

这样写,调用方就不用每次都包数组了,很灵活。

2. 判断是不是 null 或 undefined

这个简单:

if (value == null) { // 等价于 value === null || value === undefined
  // 处理空值
}

== null比分开写两个条件更简洁,而且语义清晰。


3. 判断是不是普通对象(不是数组、不是 null、不是函数等)

有时候我们需要区分“纯对象”和别的类型。

可以用这个小技巧:

function isPlainObject(obj) {
  return obj?.constructor === Object;
}

解释一下:

  • obj?. 是可选链,防止 obj 是 null/undefined
  • constructor 属性指向构造函数
  • 普通对象的构造函数就是 Object

测试一下:

isPlainObject({})           // true
isPlainObject([])           // false,数组的 constructor 是 Array
isPlainObject(null)         // false
isPlainObject(function(){}) // false,函数的 constructor 是 Function

这个方法在处理 API 返回数据时特别有用。比如:

// 假设接口可能返回对象或数组
const res = await api.getData();
if (isPlainObject(res)) {
  showUserInfo(res);
} else if (Array.isArray(res)) {
  showList(res);
}

小结

  • 判断空对象:优先用 Object.keys(obj).length === 0
  • 判断数组:用 Array.isArray()
  • 判断 null/undefined:用 value == null
  • 判断是不是普通对象:用 obj?.constructor === Object

JS的类型系统确实有点乱,但我们没必要追求完美的判断方式。只要在你的业务场景下能正确工作,就是好方法