判断一个变量是不是空对象有两步
- 变量是不是对象
- 对象是不是空的
判断变量是不是对象
var obj;
// 初级版本
typeof obj === 'object'
null
typeof 即可做一个简单的判断,但是要注意 null
因为typeof null === 'object' 为 true

所以判断是不是对象的语句如下
obj !== null && typeof obj === 'object'
[]
因为 typeof [] === 'object'

用 Array.isArray(obj) 判断

所以判断是不是对象的终极语句如下
obj !== null && typeof obj === 'object' && !Array.isArray(obj)
效果如下

Object.prototype.toString.call
评论区大佬用一个比较简单的办法解决了判断是不是对象的问题


so
Object.prototype.toString.call(obj) === '[object Object]'
判断对象是不是空对象
经过上面对象的判断之后,确定是对象的前提下,怎么确定这个对象是一个空对象呢?
Object.keys
它会先列举对象的所有可枚举属性键名到数组中,再判断数组的长度
Object.keys(obj).length === 0
对不可枚举的属性无效

JSON.stringify
JSON.stringify(obj) === {}
其无法转化函数键值对,同时对不可枚举的属性束手无策

Object.getOwnPropertyNames
Object.getOwnPropertyNames(obj).length === 0

可以获取到不可枚举的属性键,正解!!!
还要注意一种情况对象属性为 Symbol 的时候,Object.getOwnPropertyNames 无法检测出来,需要单独处理
当一个 symbol 类型的值在属性赋值语句中被用作标识符,该属性(像这个 symbol 一样)是匿名的;并且是不可枚举的。因为这个属性是不可枚举的,它不会在循环结构 “for( ... in ...)” 中作为成员出现,也因为这个属性是匿名的,它同样不会出现在 “Object.getOwnPropertyNames()” 的返回数组里。这个属性可以通过创建时的原始 symbol 值访问到,或者通过遍历 “Object.getOwnPropertySymbols()” 返回的数组。

所以要加上 Symbol 判断
Object.getOwnPropertySymbols(obj).length === 0
Reflect.ownKeys
经评论区高人指点,发现 Reflect.ownKeys 既可以解决非枚举属性也可以解决Symbol属性。


总结
终极版判断一个变量是不是空对象的代码
obj !== null
&& typeof obj === 'object'
&& !Array.isArray(obj)
&& (Object.getOwnPropertyNames(obj).length === 0)
&& (Object.getOwnPropertySymbols(obj).length === 0)
// or
(Object.prototype.toString.call(obj) === '[object Object]')
&& (Object.getOwnPropertyNames(obj).length === 0)
&& (Object.getOwnPropertySymbols(obj).length === 0)
// or
(String(obj) === '[object Object]') && (Reflect.ownKeys(obj).length === 0)
封装成函数如下
function isEmptyObj(obj) {
return obj !== null
&& typeof obj === 'object'
&& !Array.isArray(obj)
&& (Object.getOwnPropertyNames(obj).length === 0)
&& (Object.getOwnPropertySymbols(obj).length === 0)
}
// or
function isEmptyObj(obj) {
return (Object.prototype.toString.call(obj) === '[object Object]')
&& (Object.getOwnPropertyNames(obj).length === 0)
&& (Object.getOwnPropertySymbols(obj).length === 0)
}
// or
function isEmptyObj(obj) {
return (String(obj) === '[object Object]') && (Reflect.ownKeys(obj).length === 0)
}
