我发现有些初学的小伙伴在判断对象是否是空对象时用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) // 1
console.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) // 1
console.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) // true
console.log(JSON.stringify(obj) === '{}') // true
console.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) // false
console.log(getLength(obj2) === 0) // false
console.log(getLength(obj3) === 0) // false
console.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) // false
console.log(Reflect.ownKeys(obj2).length === 0) // false
console.log(Reflect.ownKeys(obj3).length === 0) // false
console.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