-1

I came across this issue while debugging an app, and the other answers do not solve this!!

With the following use case :

class Foo {
  get foo() { return 'foo'; }
}

const value = new Foo();

The following popular solutions do not work :

!Object.keys(value).length;                   // true
!Object.entries(value).length;                // true
!Object.getOwnPropertyNames(value).length;    // true

Neither is this solution :

function isEmpty(obj) {
  for (var prop in obj) {
    return false;
  }
  return true;
}
isEmpty(value);                              // true

To be clear, Foo has a getter, and should not be considered empty!

In other words, I expect these results from these use cases :

const value1 = new class {};                              // value1 is empty
const value2 = new class { get foo() { return 'foo'; } }  // value2 is not empty
const value3 = {};                                        // value3 is empty
const value4 = { foo:'foo' };                             // value4 is not empty
const value5 = Object.create(null);                       // value5 is empty
const value6 = Object.create(null); value6.foo = 'foo';   // value6 is not empty

How can this be evaluated reliably?

Yanick Rochon
  • 51,409
  • 25
  • 133
  • 214
  • 1
    https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object – JASBIR SINGH Apr 08 '22 at 15:42
  • I'm sorry, but while these may provide useful information, a good starting point, they do not answer this specific question. – Yanick Rochon Apr 08 '22 at 15:54
  • That accessor property is being created on the **prototype**, so how do you expect to deal with prototype props? *`Foo` has a getter* **No.** `value` has a getter, and it lives on its prototype. – connexo Apr 08 '22 at 16:02

1 Answers1

1

According to MDN:

When using get the property will be defined on the instance's prototype

In your Foo example:

class Foo {
  get foo() { return 'foo'; }
}

const value = new Foo();

console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(value)));
// check if 'empty' (has only "constructor")
console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(value)).length === 1);

If you want a function that covers all example cases, you can use this:

function isEmpty(obj) {
  const proto = Object.getPrototypeOf(obj);
  return (Object.keys(obj).length === 0) && (
    proto === null
    || proto === Object.prototype
    || (Object.getOwnPropertyNames(proto).length === 1)
  );
}

const value1 = new class {};                              // value1 is empty
const value2 = new class { get foo() { return 'foo'; } }  // value2 is not empty
const value3 = {};                                        // value3 is empty
const value4 = { foo:'foo' };                             // value4 is not empty
const value5 = Object.create(null);                       // value5 is empty
const value6 = Object.create(null); value6.foo = 'foo';   // value6 is not empty

[value1, value2, value3, value4, value5, value6]
  .map((v, i) => `value${i + 1} is ${isEmpty(v) ? "empty" : "not empty"}`)
  .forEach((v) => console.log(v));
User
  • 317
  • 2
  • 8