JS中如何判断一个对象是空对象

我发现有些初学的小伙伴在判断对象是否是空对象时用if(obj)或者是用if({}==={})。当你给他测试时,他才意识到问题。

判断对象是否为空的问题不仅在面试中经常被问到,在项目开发中也会经常使用到–比如我们在判断后端数据是否为空时所做的相应处理,以避免项目运行时产生问题。下面就说几种判断对象是否为空的方法。

有以下六种方式判断对象是否为空:

  • 使用JSON.striginfy()
  • 使用Object.keys()
  • for…in循环
  • Object.getOwnPropertyNames()
  • Object.getOwnPropertyNames 和 Object.getOwnPropertySymbols
  • Reflect.ownKeys

JSON.striginfy()

这是最常用的一个判断方法,该方法可以序列化对象并将其转换为相应的JSON字符串格式。

let obj = {};console.log(JSON.stringify(obj) === "{}");//返回true

⚠️注意:

如果存在未定义属性值,或函数,Symbol值,在序列化过程中,它们将被忽略或转换为空。

const obj = {  a: undefined,  b: function() {},  c: Symbol()}console.log(JSON.stringify(obj) === '{}')  // true

 

所以不是很推荐这种方式,但如果能够确认不会出现以上这种情况的话,这种方法当然是最简单的一种方式。

Object.keys()

这也是会经常用到的方式。Object.keys()返回对象的属性名组成的一个数组,若长度为0 ,则为空对象。

let obj = {}console.log(Object.keys(obj).length == 0);//返回true

⚠️注意:

只能遍历可枚举的属性,但不能遍历非枚举的属性

例如,我们先给obj定义一个属性a,将其设置成可枚举类型,结果当然是false:

const obj = {}Object.defineProperty(obj, 'a', {  value: 1,  enumerable: true})console.log(obj.a) // 1console.log(Object.keys(obj).length === 0) // false

接下来我们再将enumerable 设置成false,属性a将不会统计出来,结果显示obj为空对象:

const obj = {}Object.defineProperty(obj, 'a', {  value: 1,  enumerable: false})console.log(obj.a) // 1console.log(Object.keys(obj).length === 0) // true

for in循环

for in循环需要和hasOwnProperty结合使用来判断对象是否为空。因为在for in循环时也会遍历原型上的属性,为了排除原型上的属性,所以使用hasOwnProperty。

const obj = {}Object.prototype.a = 1 // 原型上的值
function isEmptyObj(obj) {  let flag = true  for (let o in obj) {    if (obj.hasOwnProperty(o)) {      flag = false      break    }  }  return flag}console.log(isEmptyObj(obj))  // true

⚠️注意:

这个方法同Object.keys一样,不能遍历非枚举的属性演示如上…

Object.getOwnPropertyNames()

以上两种方法都不能获取非枚举属性,那有没有办法获取到非枚举属性呢?噔噔噔…就是这个Object.getOwnPropertyNames()!Object.getOwnPropertyNames()可以获取对象本身所有属性名称(包括非枚举属性)组成的数组。

const obj = {}Object.defineProperty(obj, 'a', {  value: 1,  enumerable: false})console.log(Object.getOwnPropertyNames(obj))  // [ 'a' ]

似乎解决了前面的难题,但另一个难题又出现了—-无法获取作为名称属性的Symbol值。上代码:

const a = Symbol()const obj = {  [a]: 1}
console.log(obj)  // { [Symbol()]: 1 }console.log(Object.getOwnPropertyNames(obj).length === 0)  // trueconsole.log(JSON.stringify(obj) === '{}')  // trueconsole.log(Object.keys(obj).length === 0)  // true

好吧,是所有的方法都识别不出symbol的值。在找到完美的解决方案之前我们坚持不懈。有没有既能非枚举属性,又能识别symbol的方法嘞?答案是有滴,请看下面的方法

Object.getOwnPropertyNames 和 Object.getOwnPropertySymbols

Object.getOwnPropertyNames唯一已知的缺点是无法获取以Symbol为名的属性。而Object.getOwnPropertySymbols 只能获取以Symbol为名的属性。所以这两个方法是相互补充,一拍即合。

const a = Symbol()const obj1 = {  [a]: 1}const obj2 = {b: 2}const obj3 = {}Object.defineProperty(obj3, 'a', {  value: 1,  enumerable: false})const obj4 = {}
function getLength(obj) {  return Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj)).length}console.log(getLength(obj1) === 0)  // falseconsole.log(getLength(obj2) === 0)  // falseconsole.log(getLength(obj3) === 0)  // falseconsole.log(getLength(obj4) === 0)  // true

嗯嗯嗯,经过上面的测试,完全符合我们的预期,perfect!似乎是有点麻烦😡 我们再得寸进尺一下,有没有既能识别非枚举属性,又能识别symbol值,又很简单的方法嘞?有…继续往下看

Reflect.ownKeys

其返回值也是数组。

const a = Symbol()const obj1 = {  [a]: 1}const obj2 = {b: 2}const obj3 = {}Object.defineProperty(obj3, 'a', {  value: 1,  enumerable: false})const obj4 = {}
console.log(Reflect.ownKeys(obj1).length === 0)  // falseconsole.log(Reflect.ownKeys(obj2).length === 0)  // falseconsole.log(Reflect.ownKeys(obj3).length === 0)  // falseconsole.log(Reflect.ownKeys(obj4).length === 0)  // true

总结

JSON.striginfy(),Object.keys(),for…in循环,Object.getOwnPropertyNames()适合简单的判断,不能识别非枚举属性,不能识别symbol值。

Object.getOwnPropertyNames 和 Object.getOwnPropertySymbols和Reflect.ownKeys能识别非枚举属性,也能识别symbol值。

原创文章,作者:guozi,如若转载,请注明出处:https://www.sudun.com/ask/81540.html

(0)
guozi's avatarguozi
上一篇 2024年5月31日 上午11:59
下一篇 2024年5月31日 下午12:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注