3

Sure i can do:

var obj = {};
if(Object.keys(obj).length == 0)

but i was curious if there is a way to say:

var obj = {};
if(obj.hasKeys())

or even:

//already tested, and this doesnt work.  its true because it *is* something.
var obj = {};
if(!obj)
Fallenreaper
  • 10,222
  • 12
  • 66
  • 129
  • You do realize that even with `Object.keys` it may return incorrect result, for example when `obj` has a nontrivial prototype? – freakish Feb 12 '14 at 21:29
  • If you happen to be using jQuery: https://api.jquery.com/jQuery.isEmptyObject/. If not, the answers show you how to do it with vanilla JS – Ayush Feb 12 '14 at 21:30
  • I like vanilla JS for this. JQ is great to do stuff, but horribly inefficient to use it for EVERYTHING. – Fallenreaper Feb 12 '14 at 21:34
  • I have no idea which is the most efficient way to accomplish it. I like the short circuiting, but my bet is the one with the most votes will get the answer. – Fallenreaper Feb 12 '14 at 21:36
  • @freakish: even if the object inherited properties, the object could still be empty and thus Object.keys(o).length would be quick, native, and simple... – dandavis Feb 12 '14 at 21:39
  • @dandavis I stand corrected; I was certain `Object.keys` would include the prototype's properties, but that's not the case. – user229044 Feb 12 '14 at 21:44
  • @dandavis That depends on what OP wants (he might want an empty object as in with no properties in entire prototype chain). As for "quick" you do realize that `Object.keys(o).length` not only creates a list but also it calculates it's length which is far from being quick (unless you've meant quick as in quick in coding). Have a look at squid313's or Bergi's answer: they both avoid that overhead. – freakish Feb 12 '14 at 21:46
  • @freakish: i meant quick to code, but a perf comparison would be instructive. Since the dev or engines can cache function calls, my suggestion might not be much or any slower than a for loop iteration and in the context of a whole program, any worse than modifying every object in the environment. – dandavis Feb 12 '14 at 21:51
  • @dandavis http://jsperf.com/ways-to-detect-emptiness It depends on browser. There is not much difference in Chrome but huuuuge difference in IE (I don't know why it marked my IE as "other"). But it looks more like some strange caching to be honest, because the way IE outperformed Chrome just blew my mind. – freakish Feb 12 '14 at 21:57
  • @freakish: thanks for the link. In IE10, the Object.keys approach is about half the speed on truly empty objects, not sure which IE version you tested. I would also expect something that modifies Object.prototype would slow down all code running in the program, but a method like that wasn't included in linked test... anyways, good info, thanks! – dandavis Feb 12 '14 at 22:03

5 Answers5

4
function hasKeys(o) {
    for (var name in o)
        if (o.hasOwnProperty(name))
            return true;
    return false;
}
squid314
  • 1,394
  • 8
  • 9
  • do you need to say **hasOwnProperty** or can you say: `if(o[name]) ` – Fallenreaper Feb 12 '14 at 21:39
  • You do need to use `hasOwnProperty`. Testing `if (o[name])` actually tests the value stored under the key. For example, if you used `if (o[name])` then `hasKeys({iAmHidding: false})` would claim the object had no keys since the *value* of the property `iAmHiding` is falsy. However, falsy properties can't hide from `hasOwnProperty` and `hasKeys({iCantHide: false})` would return true. – squid314 Feb 12 '14 at 21:46
  • 2
    @squid314 However you could just simply remove `if (o.hasOwnProperty(name))` line. But that depends on what OP's defines by an "empty object". – freakish Feb 12 '14 at 21:48
  • 1
    Whether you need the `hasOwnProperty` does depend on the exact definition of "empty". Given the example @Fallenreaper provided, which uses `Object.keys(o).length`, I assumed that was his/her definition of "empty". `Object.keys()` specifies that it returns a list of "the objects *own enumerable* properties" (emphasis mine). Therefore, I needed an enumeration which guarantees to only return true if the property is the object's own. – squid314 Feb 12 '14 at 21:53
3

This will detect enumerable properties, and is inherited from the Object.prototype like your example:

Object.defineProperty(Object.prototype, "hasKeys", {
    configurable: true,
    value: function() {
        for (var _ in this) return true;
        return false;
    }
});

To detect non-enumerable properties, you would have to use Object.getOwnPropertyNames.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • It seems the overall answer comes down to: create a function or have an addendum to the base Object prototype. – Fallenreaper Feb 12 '14 at 22:09
  • Yes, if that was your question: There is neither a native function nor an operator to do this. – Bergi Feb 12 '14 at 22:11
  • just one suggestion: i can imagine that arbitrary JSON data might contain something like "hasKeys: false", which would throw if you tried to call it. The fix would be to namespace the global object method ala "_hasKeys" (better), or use a named function instead of a method to avoid conflict (best). – dandavis Feb 12 '14 at 22:13
  • @dandavis: Yeah, if you fear collisions you cannot use `Object.prototype`, you should use a static function instead (avoid underscore methods). I personally have defined all my object helper on the `Object` "namespace", like `Object.hasKeys(obj)`. – Bergi Feb 12 '14 at 22:18
1

May be best to create a function and call it when you need it:

function isObjectEmpty(object) {
 for(var i in object) 
  if(object.hasOwnProperty(i))
    return false;

  return true;
}

At least using this method name you, and your fellow coders, can clearly see what you're testing the object for.

Stu1986C
  • 1,452
  • 1
  • 18
  • 34
1

without making you're own function, you can at least use a shorter syntax thanks to JS's ability to coerce:

if( Object.keys({})[0] ) alert("non-empty object");

the only caveat with this dead-simple approach is if you actually want to detect inherited or computed properties, or if you somehow have an object with a blank key, which is (hopefully) very uncommon. ex: {"":0}...

note: I altered my orig answer to make it slightly more readable.

dandavis
  • 16,370
  • 5
  • 40
  • 36
0

No. You could make it work...

Object.prototype.hasKeys = function () {
  return Object.keys(this).length > 0
}

... but you shouldn't; modifying prototypes of built-in classes in JavaScript is a pretty bad idea. You'd be better off just writing a utility method like is_empty(obj), or using a library that already provides something like that, like Underscore's isEmpty or jQuery's isEmptyObject for example.

user229044
  • 232,980
  • 40
  • 330
  • 338