How to determine whether the object itself is empty in js?
Prerequisite knowledge:
The enumerable property enumerable in the js object: used to control whether the described property will be included in the for...in loop (unless the property name is a Symbol). Specifically, if the enumerable of an attribute is false, the following three operations will not obtain the attribute.
for...in
cycleObject.keys
methodJSON.stringify
method,
enumerable is false. Although the above operation cannot obtain the attribute, the value of the attribute can still be obtained.
for...in
The difference between and Object.keys
is: the former includes the properties that the object inherits from the prototype object, while the latter only includes the properties of the object itself. If you need to get all the properties of the object itself, regardless of whether the enumerable value is true/false, you can use Object.getOwnPropertyNames
the method.
How to determine whether an object is empty is a problem we often encounter in development. Today we will talk about several commonly used methods and how we use them in different scenarios.
-
JSON.stringify
JSON.stringify
The method can serialize the object and convert it into the corresponding JSON format.const obj = { }; console.log(JSON.stringify(obj) === '{}') // true
Disadvantages: If
undefined
any function and symbol values exist, they will be ignored (when appearing in attribute values of non-array objects) or convertednull
(when appearing in arrays) during the serialization process.Example:
const obj = { a: undefined, b: function() { }, c: Symbol() } console.log(JSON.stringify(obj) === '{}') // true
-
for…in combination hasOwnProperty
Use
for in
to traverse the current object:const obj = { } Object.prototype.a = 1 function isEmptyObj(obj) { let flag = true for (let o in obj) { flag = false break } return flag } console.log(isEmptyObj(obj)) // false
Since
for in
when performing object traversal, the properties on the object prototype will be traversed, and we only want to get its own properties, we can usehasOwnProperty
to achieve this, as follows: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
Disadvantage:
for in
Cannot traverse non-enumerable properties. -
Object.keys
Object.keys
Will return an array of enumerable properties of the object itself, without traversing the properties on the prototype.const obj = { } Object.prototype.a = 1 console.log(Object.keys(obj).length === 0) // true
Disadvantages:
Object.keys
andfor in
can only traverse enumerable properties, not non-enumerable properties.We use
Object.defineProperty
the propertyenumerable
to be set tofalse
test, the example is as follows:const obj = { } Object.defineProperty(obj, 'a', { value: 1, enumerable: false }) console.log(obj.a) // 1 console.log(isEmptyObj(obj)) // true console.log(Object.keys(obj).length === 0) // true
-
Object.getOwnPropertyNames
Use
Object.getOwnPropertyNames
can get an array composed of all attribute names of the object itself (including non-enumerable attributes).const obj = { } Object.defineProperty(obj, 'a', { value: 1, enumerable: false }) console.log(Object.getOwnPropertyNames(obj)) // [ 'a' ]
Disadvantages: You cannot get
Symbol
the value as the attribute of the name. The aboveJSON.stringify
and methods cannot getfor in
the value as the attribute of the name. Examples are as follows:Object.keys
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(isEmptyObj(obj)) // true console.log(Object.keys(obj).length === 0) // true
-
Object.getOwnPropertyNames 结合Object.getOwnPropertySymbols
It is known that
Object.getOwnPropertyNames
the only disadvantage is that you cannot getSymbol
the attribute with the value as the name, butObject.getOwnPropertySymbols
you can only getSymbol
the attribute with the value as the name. Is the combination of the two a perfect solution? Let’s do a simple test: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
After testing, the above method can indeed be solved, but it is more cumbersome. Is there a better method? The answer is yes.
-
Reflect.ownKeys
Reflect.ownKeys
The method returns an array composed of the properties of the target object itself. Its return value is equivalent toObject.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
: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
Summarize
When judging whether an object is empty, Reflect.ownKeys
the method is most perfect.