一道面试题:怎么判断一个对象是空对象{}

125 阅读2分钟

相信不少人遇到过这个问题,不管是面试还是开发过程中。

JSON.stringify

然后会有几种方法用以判断该对象是否为空对象{},比如一些人应该会想到使用JSON.stringify

const obj = {}
console.log(JSON.stringify(obj) === '{}') // 输出true

验证可以啊。然后我修改一下代码

const obj = {
     f: ()=>{}
}
console.log(JSON.stringify(obj) === '{}') // 输出还是true

什么情况?这是因为JSON.stringify字符串话有副作用,其中之一就是将函数丢失。除了丢失函数,还有以下副作用:

  1. 丢失函数和原型:因为JSON格式不支持函数和原型的序列化
  2. 日期对象转换:JSON.stringify()方法会将日期对象转换为字符串,而不是保留日期对象的原始类型。在反序列化时,需要手动将字符串转换回日期对象
  3. 循环引用问题:如果对象中存在循环引用(即对象的属性之间相互引用),JSON.stringify() 方法会抛出错误
  4. 丢失特殊值:JSON.stringify()方法会将undefinedNaNInfinity序列化为 null
  5. 丢失对象属性顺序:在对象中,属性的顺序在JSON字符串中不保证与原始对象相同

Object.keys

既然如此那我换一个别的,比如使用Object.keys,获取是否有属性。

  const obj = {
  }
  console.log(Object.keys(obj).length === 0) // 输出true

也可以啊。稍等我处理一下对象,我用Object.defineProperty处理一下。

const obj = {}

Object.defineProperty(obj, 'key', {
      value: 'test',
      enumerable:false // 不可枚举
})
console.log(Object.keys(obj).length === 0) // 输出true

什么情况?这是因为不可枚举下的属性值,不可以被Object.keys获取到。

for in

那我再换一种方式,我用for in的方式

 for(let key in obj) {
     console.log(key, 'key') // 不会打印出来
 }

这个也不行。于是再用JSON.stringify试试

const obj = {}

Object.defineProperty(obj, 'key', {
       value: 'test', 
       enumerable:false // 不可枚举
})
console.log(JSON.stringify(obj) === '{}') // 输出true

实际上,JSON.stringify也会忽略不可枚举类型。那么究竟该用什么判断呢?

Object.getOwnPropertyNames

const obj = {}
Object.defineProperty(obj, 'key', {
     value: 'test',
     enumerable:false // 不可枚举
})
console.log(Object.getOwnPropertyNames(obj)) // 输出['key']

这个倒是可以,然后我再改下

const obj = {
  [Symbol("id")]: 123
}

console.log(Object.getOwnPropertyNames(obj)) // 输出[]

事实上,Object.getOwnPropertyNames只返回字符串键的数组,无法判断对象是否包含Symbol键,再换。

Reflect.ownKeys

const obj = {}
Object.defineProperty(obj, 'key', {
      value: 'test',
      enumerable:false // 不可枚举
})
console.log(Reflect.ownKeys(obj)) // 输出['key']

再试

 const obj = {
    [Symbol("id")]: 123
 }
 
 console.log(Reflect.ownKeys(obj)) // 输出[Symbol(id)]

所以Reflect.ownKeys才是最佳解决方案。

本文完。