189

I was encountering a lot of bugs in my code because I expected this expression:

Boolean([]); to evaluate to false.

But this wasn't the case as it evaluated to true.

Therefore, functions that possibly returned [] like this:

// Where myCollection possibly returned [ obj1, obj2, obj3] or []
if (myCollection)
{
  // ...

} else
{
  // ...
}

did not do expected things.

Am I mistaken in assuming that [] an empty array should evaluate to false?

Also, Is this behavior consistent in all browsers? Or are there any gotchas there too? I observed this behavior in Google Chrome by the way.

Alex Spurling
  • 54,094
  • 23
  • 70
  • 76
racl101
  • 3,760
  • 4
  • 34
  • 33
  • 11
    arrays are objects, objects are truthy. just ask for array.length, if not zero, it will be truthy. when you explicitly convert to Boolean, the array turns into an empty string first, then the empty string turns into false. – dandavis Oct 02 '13 at 20:26
  • 2
    Why don't you use `myCollection.length > 0`? – Steve Oct 02 '13 at 20:26
  • 1
    @Steve - that won't work if `myCollection` happens to be `null` or `undefined`. You need to use `if(myCollection && myCollection.length > 0)`. – Ted Hopp Oct 02 '13 at 20:29
  • @TedHopp - of course... I was just pointing out that `myCollection.length > 0` offers a boolean value that is doing what the OP asked for... he still needs to do the work from there. – Steve Oct 02 '13 at 20:37
  • 3
    possible duplicate of [javascript empty array seems to be true and false at the same time](http://stackoverflow.com/questions/5491605/javascript-empty-array-seems-to-be-true-and-false-at-the-same-time) – bummi Jan 02 '15 at 23:04
  • guys you don't need to use `myArray.length > 0` because if length is 0, it will return 0 which is false and if it returns any other length greater than 0 it will be true by default. – Kunok Aug 28 '17 at 13:18

8 Answers8

205

From http://www.sitepoint.com/javascript-truthy-falsy/

The following values are always falsy:

  • false
  • 0 (zero)
  • 0n (BigInt zero)
  • "" (empty string)
  • null
  • undefined
  • NaN (a special Number value meaning Not-a-Number!)

All other values are truthy, including "0" (zero in quotes), "false" (false in quotes), empty functions, empty arrays ([]), and empty objects ({}).

Regarding why this is so, I suspect it's because JavaScript arrays are just a particular type of object. Treating arrays specially would require extra overhead to test Array.isArray(). Also, it would probably be confusing if true arrays behaved differently from other array-like objects in this context, while making all array-like objects behave the same would be even more expensive.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 56
    If you test the expression `[] == false` it evaluates to `true`. – m.rufca Apr 24 '18 at 18:06
  • 4
    @m.rufca See https://stackoverflow.com/questions/5491605/empty-arrays-seem-to-equal-true-and-false-at-the-same-time – Barmar Apr 24 '18 at 19:29
  • there is a handful table showing unexpected situations using `==` comparator in the link you posted. I commented just to be careful when expecting true or false evaluation. – m.rufca Apr 24 '18 at 21:10
  • Yes, there's a difference between writing `if(xxx)` and `if(xxx == true)`, and between `if(!xxx)` and `if(xxx == false)`. You should only use the `==` forms when you know the value is a boolean (and even then many programmers consider it poor style). – Barmar Apr 24 '18 at 21:15
  • 13
    This doesn't really answer the question, which was WHY. Why is an empty array truthy, when an empty string is falsy? As a deliberate design decision this feels very poor. – Esa Lindqvist May 14 '18 at 13:03
  • @EsaLindqvist Questions about language design are not really on-topic, they're opinion-based. But arrays are just objects that happen to have a few special properties (e.g. `length`). Objects are all truthy. – Barmar May 14 '18 at 15:27
  • @Barmar yes but there must be some reasoning behind it. That's the question. – Esa Lindqvist May 15 '18 at 15:59
  • @EsaLindqvist It's probably because arrays are objects, objects are all truthy, and they didn't want to make a special case for them. – Barmar May 15 '18 at 17:24
  • There already are special cases for String, Number and Boolean wrapper objects aren't there? – Esa Lindqvist May 16 '18 at 04:44
  • 1
    Maybe, because those are required to act like the primitive objects. But Javascript doesn't have primitive arrays. – Barmar May 16 '18 at 04:46
  • How about "null" and "undefined"? – MrBoJangles Mar 16 '22 at 22:24
  • 1
    @EricDuminil I didn't know about BigInt when I wrote the answer 9 years ago. But I think it's enough to say that all forms of zero are falsey – Barmar Sep 08 '22 at 19:54
  • 1
    @EricDuminil Updated it – Barmar Sep 08 '22 at 20:00
  • if you test the expression... here is an expression for `truthy` (not `true`): `a = ([]) ? 'truthy': 'falsey'` – maxkoryukov Sep 30 '22 at 11:50
48

You should be checking the .length of that array to see if it contains any elements.

if (myCollection) // always true
if (myCollection.length) // always true when array has elements
if (myCollection.length === 0) // same as is_empty(myCollection)
DevlshOne
  • 8,357
  • 1
  • 29
  • 37
15

While [] equals false, it evaluates to true.

yes, this sounds bad or at least a bit confusing. Take a look at this:

const arr = [];
if (arr) console.log("[] is truethy");
if (arr == false) console.log("however, [] == false");

In practice, if you want to check if something is empty, then check the length. (The ?. operator makes sure that also null is covered.)

const arr = []; // or null;
if (!arr?.length) console.log("empty or null")
bvdb
  • 22,839
  • 10
  • 110
  • 123
  • 5
    Woah, that [_optional chaining operator_ `?.`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining). That seems pretty new (and useful). Thanks for my TIL. – Константин Ван Jan 27 '21 at 23:58
  • 1
    @КонстантинВан I guess it needs a warning about compatibility. :-) Thank you for pointing that out. – bvdb Jan 28 '21 at 08:12
  • 1
    Why am I only now finding out about the optional chaining operator? and the related [Nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator) So good! Thanks – Dave Apr 14 '21 at 01:39
13
[]==false  // returns true

This evaluates to true, because of the Abstract Equality Algorithm as mentioned here in the ECMA Specification #Section 11.9.3

If you run through algorithm, mentioned above.

In first iteration, the condition satisfied is,

Step 7: If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).

Hence the above condition transforms to -> [] == 0

Now in second iteration, the condition satisfied on [] == 0:

Step 9: If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.

[] is an object, henceforth, on converting to primitive, it transforms to an empty string ''

Hence, the above condition transforms to -> '' == 0

In third iteration, condition satisfied, is:

Step 5: If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.

As we know, empty string, '' is a falsy value, hence transforming an empty string to number will return us a value 0.

Henceforth, our condition, will transform to -> 0 == 0

In fourth iteration, the first condition is satisfied, where the types are equal and the numbers are equal.

Henceforth, the final value of the [] == false reduces to 0 == 0 which is true.

Hope this answers your question. Otherwise, you can also refer this youtube video

Abir
  • 170
  • 2
  • 5
  • 1
    I've been hoping for this answer for almost a decade. – Wyck Oct 17 '22 at 14:38
  • 1
    Finally an answer that references the language specification, – bvdb Oct 19 '22 at 09:02
  • `![] == false // returns true as well` – EliSherer Jan 24 '23 at 13:39
  • Yes, @EliSherer, that's expected only. Focus on second iteration from the above algorithm, where object is converted to a primitive, `(![]).toString()` , it will internally, result to empty string, that is `falsy` value. Henceforth, `false` Which means, third and fourth iteration remains same, and result for above comment is `true` as well. Remember my friend, `!([]==false)` will be `false` `![]==false` will be `true` – Abir Jan 25 '23 at 12:01
1

I suspect it has something to do with discrete math and the way a conditional (if then) works. A conditional has two parts, but in the instance where the first part doesn't exist, regardless of the second part, it returns something called a vacuous truth.

Here is the example stated in the wikipedia page for vacuous truths

"The statement "all cell phones in the room are turned off" will be true when no cell phones are in the room. In this case, the statement "all cell phones in the room are turned on" would also be vacuously true"

The wikipedia even makes specific mention of JavaScript a little later.

https://en.wikipedia.org/wiki/Vacuous_truth#:~:text=In%20mathematics%20and%20logic%2C%20a,the%20antecedent%20cannot%20be%20satisfied.&text=One%20example%20of%20such%20a,Eiffel%20Tower%20is%20in%20Bolivia%22.

0

Also want to add, that all objects in JavaScript (arrays are objects too) are stored in memory as links and these links are always not null or zero, that's why Boolean({}) === true, Boolean([]) === true.

Also this is the reason why same objects (copied by value not the link) are always not equal.

{} == {} // false

let a = {};
let b = a; // copying by link
b == a // true
Toni
  • 1,555
  • 4
  • 15
  • 23
ZloiGoroh
  • 411
  • 4
  • 11
0

As in JavaScript, everything is an object so for falsy and empty, I use the below condition:

if(value && Object.keys(value).length){
    // Not falsy and not empty
}
else{
    // falsy or empty array/object
}
Shivam Sharma
  • 1,277
  • 15
  • 31
0

In JavaScript, both an empty string and an empty array are considered falsey values. They are treated as false when evaluated in a Boolean context. It seems there might be some confusion regarding this aspect.

To clarify, in JavaScript, the following values are considered falsey:

  1. false: The boolean value false.
  2. 0: The number zero.
  3. NaN: Not-a-Number, which represents an invalid or unrepresentable value.
  4. null: Represents the intentional absence of any object value.
  5. undefined: Denotes a variable that has been declared but has not been assigned a value.
  6. '': An empty string.
  7. document.all: A historical artifact that is no longer recommended to use.

These values are coerced to false when encountered in a Boolean context, such as in an if statement or a conditional expression.

Now, it's worth noting that an empty array [] is still a valid JavaScript object and is considered a truthy value. However, when used in a Boolean context, such as in an if statement, the empty array is automatically coerced to its Boolean representation, which is false.

For example:

if ([]){
  console.log("This will not be executed.");
}

if (''){
  console.log("This will not be executed either.");
}

if (0){
  console.log("Nor this.");
}

if (null){
  console.log("Neither this.");
}

if (undefined){
  console.log("Or this.");
}

In the above code, none of the statements inside the if blocks will be executed because all the values inside the parentheses are considered falsey.

So, in JavaScript, both an empty string and an empty array are falsey values, meaning they are treated as false when evaluated in a Boolean context.

Albert Einstein
  • 7,472
  • 8
  • 36
  • 71