最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

"Falsy or empty" in JavaScript: How to treat {} and [] as false - Stack Overflow

programmeradmin2浏览0评论

[] and {} are truthy in javascript.

But I want to treat them as false, and I would love to know how to do it in the least number of characters possible: without external libraries or separate functions, and small enough to fit fortably between the parentheses of a conditional.

In other words:

What is the most concise way possible to check an unknown variable (that could be of any type) and return false if either of these apply: a) it's already falsy; or b) it's {} or []?

[] and {} are truthy in javascript.

But I want to treat them as false, and I would love to know how to do it in the least number of characters possible: without external libraries or separate functions, and small enough to fit fortably between the parentheses of a conditional.

In other words:

What is the most concise way possible to check an unknown variable (that could be of any type) and return false if either of these apply: a) it's already falsy; or b) it's {} or []?

Share Improve this question asked Oct 20, 2013 at 10:17 supertruesupertrue 2,0995 gold badges31 silver badges50 bronze badges 2
  • Why do you need to do this? It's not easy, as T.J. Crowder's answer shows, but more to the point, it shouldn't usually be necessary. Why are you in a situation where you don't know whether you're dealing with an array, an object, or something else, and yet need to figure out whether it's falsey by these criteria? – Mark Amery Commented Oct 20, 2013 at 10:30
  • If it doesn't return false, what should it return? – RobG Commented Oct 20, 2013 at 11:04
Add a ment  | 

3 Answers 3

Reset to default 4

The most concise way with an array is !arr.length. Of course, that assumes you haven't added any non-index properties to the array (which is a perfectly valid thing to do). And as Qantas 94 Heavy points out in the ments, an array that's empty can have its length set to a non-zero value without gaining any actual entries.

Objects are more tricky. What's an "empty" object? One with no properties at all? One with no enumerable properties? What about properties from its prototype, if any?

If no enumerable properties does it for you, in ES5 you can use !Object.keys(obj).length. If you can't count on ES5, you have to have a loop:

var empty = true;
var key;
for (key in obj) {
    // Add an `obj.hasOwnProperty(key)` check here if you want to filter out prototype properties
    empty = false;
    break;
}

...which is obviously fairly ungainly.

You've said you don't want separate functions, but of course that's the best way to do this:

var isFalsey = (function() {
    var toString = Object.prototype.toString;

    function isFalsey(x) {
        var key;

        if (!x) {
            return true;
        }
        if (typeof x === "object") {
            if (toString.call(x) === "[object Array]") {
                return !x.length; // Assumes no non-element properties in the array
            }
            for (key in x) {
                // Add an `x.hasOwnProperty(key)` check here if you want to filter out prototype properties
                return false;
            }
            return true;
        }

        return false;
    }

    return isFalsey;
})();

Example with tests (source)

Given you have variable x to check:

!(!x || x.length === 0 || JSON.stringify(x) === '{}')

Here we go from the back, lets check if x is empty:

  1. it may be already falsy: !x
  2. it is Array and its length is zero: x.length === 0
  3. it is exactly {} object: JSON.stringify(x) === '{}'

Be careful with JSON.stringify method. It is available for majority of modern browsers, but not for IE6,7 if you need to support them. You should check at caniuse/JSON.

Any of this conditions being true will result in variable x to be empty.

So we need or's (||) and outer ! to invert result to check if x is not empty.

EDIT:

More concise way to do 3rd check would be due to @David remark (JSON.stringify will not work with object containing methods like {a: function(){ console.log("test"); }}):

(function (x){ for (key in x) { return 0; } return 1; })(x)

So resulting expression is:

!(!x || x.length === 0 || (function (x){ for (key in x) { return 0; } return 1; })(x))

EDIT:

If you wanna support only modern browser, than just use ecmascript 5 feature:

// Given x is defined
!(!x || typeof x === 'object' && !Object.keys(x).length)

If you know that the value is either an instance of Array or any other primitive (and not a general object,) than you can just put a + sign before the object and pare check if it's falsy, like so:

> +[] == false
true
> +[1,2] == false
false
> +[] == false
true
> +true == false
false
> +'hello' == false
false
> +25 == false
false
> +false == false
true

Dealing with a general instance of object is more plicated as you can see:

> +{} == false
false
> +{'a': 'b'} == false
false

Or if you know that the value in question is definitely not a primitive, and you are using ES 5, then you can use Object.keys to get all the keys of the object as an array and then the check bees like this:

> +empty_obj == false || Object.keys(empty_obj) == false
true
> +obj == false || Object.keys(obj) == false
false

But if it is a primitive, you are in trouble:

> +true == false || Object.keys(true) == false
TypeError: Object.keys called on non-object
    at Function.keys (native)
    at repl:1:27
    at REPLServer.self.eval (repl.js:110:21)
    at Interface.<anonymous> (repl.js:239:12)
    at Interface.EventEmitter.emit (events.js:95:17)
    at Interface._onLine (readline.js:202:10)
    at Interface._line (readline.js:531:8)
    at Interface._ttyWrite (readline.js:760:14)
    at ReadStream.onkeypress (readline.js:99:10)
    at ReadStream.EventEmitter.emit (events.js:98:17)

All in all, you can play around with the ||, && and == operators to try to find something short that will work in all cases all day, but I'm not sure that it's possible.

So, in summary, I would remend just using a function like the one defined in @T.J. Crowder's answer.

发布评论

评论列表(0)

  1. 暂无评论