# How does the ~[] construction work in JavaScript?

I’ve come across a working JavaScript code that I can’t explain.

For example:

`+[]===0`

`-[]===0`

`~[]===-1`

`~-~[]===-2`

`~-~-~-~-~[]===-5`

`~-~-~-~-~[]+~[]===-6`

`~+~[]===0`

`~+~+~[]===-1`

`~+~+~+~[]===0`

Can you explain the logic of these expressions?

### 5 Solutions collect form web for “How does the ~[] construction work in JavaScript?”

`[]`

is an empty array object, so:

+[]: force empty array to be positive integer, aka 0, which is === to 0

-[]: force empty array to be negative integer, aka 0, which is === to 0

~[]: bitwise NOT empty array, which evaluates to -1, which is === to -1

~-~[]: bitwise NOT of negated NOTted empty array: `~-(-1) -> ~1 -> -2`

etc…

When you use the `+`

or `-`

operator on anything, it calls `Number`

on it. `Number([])`

returns `0`

, so you get your first two answers.

The `~`

operator is bitwise NOT. Basically it inverses all the bits in a number, which changes `0`

to `-1`

. More on bitwise operators here.

The rest are just combinations of those cases. You can pretty much combine those things to make any number you want.

Instead of just restating the result you demonstrated in the question, I’ll try to give a description of *why* you get that result.

**Explanation**

Taking only the first example (because the rest will do something similar), we can follow the specification to see what happens.

From 11.4.6 Unary + Operator, we can see that a `ToNumber`

conversion takes place.

Return ToNumber(GetValue(expr)).

From 9.3 ToNumber we see that if given an Object (like your Array), a `ToPrimitive`

conversion takes place followed by another attempt at `ToNumber`

.

ObjectApply the following steps:

- Let primValue be ToPrimitive(input argument, hint Number).
- Return ToNumber(primValue).

From 9.1 To Primitive, if `ToPrimitive`

gets an Object, we can see that its `[[DefaultValue]]`

is fetched:

ObjectReturn a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.

From 8.12.8 [[DefaultValue]] (hint), what will ultimately happen will be that `toString()`

will be called on the Array, and returned. This string gets sent to the recursive `ToNumber`

as described above.

So what happens when `ToNumber`

conversion is done on a String? Well it is described in 9.3.1 ToNumber Applied to the String Type, and is a bit lengthy. Simpler is to just do the conversion directly, and see what happens:

```
Number(""); // result is 0 on an empty string
Number(" "); // result is 0 on a string with only whitespace
Number("123"); // result is 123 on a numeric string
Number(" 123 ");// result is 123 on a numeric string with leading & trailing spaces
Number("abc"); // result is NaN (not a number) on non-numeric strings
```

So the question is, what string do we get back from our Array. Again, this is easy to simply test.

```
[].toString(); // result is "" (empty string)
```

Since the result is an empty string, and a `ToNumber`

conversion of an empty string is `0`

as shown above, that would mean we are comparing `0 === 0`

.

It would be the same as if we did:

```
Number( [].toString() ) === 0; // true
```

Or to draw it out a bit more:

```
var x = [];
x = x.toString(); // ""
x = Number( x ); // 0
x === 0; // true
```

**More toString results.**

To show more `toString`

conversions of Arrays, consider the following:

```
[1].toString(); // "1"
[1,2,3].toString(); // "1,2,3"
["a",1,"b",2].toString(); // "a,1,b,2"
```

So to do a `ToNumber`

conversion on the above Arrays, the first would give us a number, and the last two would result in `NaN`

.

```
Number([1]); // 1
Number([1,2,3]); // NaN
Number(["a",1,"b",2]); // NaN
```

**Some proof**

To provide further proof that this `toString()`

conversion happens before the `ToNumber`

conversion, we can actually modify `Array.prototype.toString`

to provide a different result, and any `ToNumber`

conversions will use that modified result.

```
Array.prototype.toString = function() {
var n = 0;
for( var i = 0; i < this.length; i++ ) {
n += this[i];
}
return n;
};
```

Here I’ve replaced the `toString`

on `Array.prototype`

with a function that sums the Array. Obviously you don’t want to do this, but we can show how we will now get a different result.

```
Number([1,2,3]); // 6
+[1,2,3]; // 6
```

So now you can see that the `ToNumber`

conversion of our Array that would previously have resulted in `NaN`

is now resulting in the sum of the items in the Array.

I’ll do my best:

`[]===0`

is of course false because `[]`

is not exactly equal to 0. However, `[]==0`

is true because an implicit cast exists.

`+`

and `-[]`

work because the plus or minus casts `[]`

to a real number.

`~0`

(the bitwise inverse of 0) is -1. Thus `~[]===-1`

works.

The others work just by subtracting or adding -1 a bunch of times.

I believe, correct me if I’m wrong, but adding to an array (as in, adding a value to an array rather than adding a value into an array) casts it to a number. The rest is just using basic +, – operators (the tilde (~) is a bitwise NOT) to modify the number and then an equation.

```
So [] == array ([]);
[] + 1 == number (0);
+[]===0 (true)
```