Yes, all the rules of type conversion applied by the equals operator are described on the ECMA-262 specification, in The Abstract Equality Comparison Algorithm.
The algorithm might look quite complex but it can be summarized to the following cases:
The type the two operands is the same:
- For primitives (String, Number, Boolean, Null, Undefined)
- Return true if the value is exactly the same
- For the Object type
- Return true if the two references point to the same object
If the types of the two operands differ
- If the type of one operand is either Null or Undefined
- Return true only if the other operand value is either
null
or undefined
- If one of the operands is of type Boolean or Number
- (after some steps) Convert the other operand to Number and compare
If one of the operands is an Object and the other is a primitive
- Perform Object-to-Primitive conversion on the Object and compare again
The Object-to-Primitive conversion is made through an abstract operation called ToPrimitive
, this method will try to convert the object to a primitive value, using the internal [[PrimitiveValue]]
method.
This will try to ejecute the object's valueOf
and toString
methods, and it will take the value of the first that returns a primitive value.
In the case those two methods don't return a primitive, or they aren't callable, a TypeError
is thrown, e.g.:
1 == { toString:null } // TypeError!
The above statement will produce a TypeError
because the default Object.prototype.valueOf
method doesn't do anything more than actually the same object instance (this
, not a primitive value) and we are setting an own toString
property that's not a function.
A friend made small tool that might be interesting to you, it shows all the steps and recursive comparisons made between types:
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…