When == is used to compare things of different types, like an array ([null]) and false, it has specific steps it goes through, called the Abstract Equality Algorithm (quoted below) to try to coerce them to things that it can compare. (Because == is the "loose" equality operator.)
First it sees if either operand is null or undefined, but in this case neither is.
Then it sees if it's comparing a number and a string, but that's not true in this case either.
Then it seems if either operand is a boolean, which of course on of these is. Since one of them is a boolean, it does an abstract operation called ToNumber in the spec to convert the other one to a number and does another ==. (The Number function, when used as a function and not a constructor, is basically a wrapper for that abstract ToNumber operation.)
So
[null] == false
becomes
0 == false
...because ToNumber([null]) coerces its argument to a string (via ToPrimitive), getting "", and then converts that to 0.
So now == has something where one of the operands is a number. SO it converts the other one to a number as well. Number(false) is 0.
Thus, [null] == false is true.
So what about [null, null] == false? When converting [null, null] to a string, we get ",", which ToNumber can't turn into a valid number. So it converts it to NaN. One of the fun things about NaN is that it's a number, but it's never equal to anything else. So:
[null, null] == false
becomes
NaN == false
becomes
NaN == 0
...which is false, because (again) NaN is never equal to anything.
Here's that Abstract Equality Algorithm:
- ReturnIfAbrupt(
x).
- ReturnIfAbrupt(
y).
If Type(x) is the same as Type(y), then
a) Return the result of performing Strict Equality Comparison x === y.
If x is null and y is undefined, return true.
- If
x is undefined and y is null, return true.
- If Type(
x) is Number and Type(y) is String,
return the result of the comparison
x == ToNumber(y).
- If Type(
x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
- If Type(
x) is Boolean, return the result of the comparison
ToNumber(x) == y.
- If Type(
y) is Boolean, return the result of the comparison
x == ToNumber(y).
- If Type(
x) is either String, Number, or Symbol and Type(y) is Object, then
return the result of the comparison
x == ToPrimitive(y).
- If Type(
x) is Object and Type(y) is either String, Number, or Symbol, then
return
the result of the comparison ToPrimitive(x) == y.
- Return
false.