Let's get technical. I'll explain the logic with quotes from the ECMAScript Standard 262.
The expression [] ? 1 : 2
is very simple:
11.12 Conditional Operator ( ? : )
- Let lref be the result of evaluating LogicalORExpression.
- If ToBoolean(GetValue(lref)) is true, then
- Let trueRef be the result of evaluating the first AssignmentExpression.
- Return GetValue(trueRef).
- Else
- Let falseRef be the result of evaluating the second AssignmentExpression.
- Return GetValue(falseRef)
9.2 ToBoolean
- Undefined: false
- Null: false
- Boolean: The result equals the input argument (no conversion).
- Number: The result is false if the argument is +0, 0, or NaN; otherwise the result is true.
- String: The result is false if the
argument is the empty String (its length is zero); otherwise the
result is true.
- Object: true
So it's true.
Now for the wild ride of what happens when you use the double equals operator. Perhaps this will help explain why you should never do this.
The behavior of == is explained in in section 11.9.3: The Abstract Equality Comparison Algorithm.
For x == y where x = [] and y = false, this happens:
11.9.3: The Abstract Equality Comparison Algorithm
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y)
9.3 ToNumber
The result is +0 if the argument is
false.
Now we have [] == 0
11.9.3: The Abstract Equality Comparison Algorithm
If Type(x) is Object and Type(y) is either String or Number, return
the result of the comparison ToPrimitive(x) == y.
9.1 ToPrimitive
Return 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.
8.12.8 DefaultValue:
When the [[DefaultValue]] internal method of O is called with no
hint, then it behaves as if the hint were Number
- Let valueOf be the result of calling the [[Get]] internal method of object O with argument "valueOf".
- If IsCallable(valueOf) is true then,
- Let val be the result of calling the [[Call]] internal method of valueOf, with O as the this value and an empty argument list.
- If val is a primitive value, return val
- Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".
- If IsCallable(toString) is true then,
- Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and an empty argument list.
- If str is a primitive value, return str.
I assume this first attempts valueOf and then rejects it because the result is the same array you started with. It then calls toString on Array, which seems to be universally implemented as a comma separated list of its values. For empty arrays like this one, that results in empty string.
Now we have '' == 0
11.9.3: The Abstract Equality Comparison Algorithm
If Type(x) is String and Type(y) is Number, return the result of the
comparison ToNumber(x) == y
9.3.1 ToNumber Applied to the String Type
A StringNumericLiteral that is empty or contains only white space is
converted to +0.
Now we have 0 == 0
11.9.3: The Abstract Equality Comparison Algorithm
If x is the same Number value as y, return true
Awesome. It's true. Pretty convoluted way of getting here though.