11.9.3 Equality comparison algorithm

2010-05-17

Code: (Meta Ecma)
function EqualityComparison(x, y) {
if (Type(x) == Type(y)) {
if (Type(x) == 'undefined') return true;
if (Type(x) == 'null') return true;
if (Type(x) == 'number') {
// nan never matches anything
if (isNaN(x)) return false;
if (isNaN(y)) return false;
// zeroes match (unlike SameValue)
if (x === -0 && y === +0) return true;
if (x === +0 && y === -0) return true;
// now just check values
return x == y;
// note that the specification checks number
// values first, zeroes later, then returns false.
}
if (Type(x) == 'string') return x == y;
if (Type(x) == 'boolean') return x == y;
// x and y are objects...
return x == y; // "refer to same object"
}
// x and y are not same type: coerce one
// undefined equals null
if (x === null && y === undefined) return true;
if (x === undefined && y === null) return true;
// if comparing number to string, coerce to number
if (Type(x) == 'number' && Type(y) == 'string') return x == ToNumber(y);
if (Type(x) == 'string' && Type(y) == 'number') return ToNumber(x) == y;
// if bool to number, coerce to number
if (Type(x) == 'boolean' && Type(y) == 'number') return ToNumber(x) == y;
if (Type(x) == 'number' && Type(y) == 'boolean') return x == ToNumber(y);
// string or number to object, coerce object to primitive and try again
if ((Type(x) == 'string' || Type(x) == 'number') && Type(y) == 'object') return x == ToPrimitive(y);
if (Type(x) == 'object' && (Type(y) == 'string' || Type(y) == 'number')) return ToPrimitive(x) == y;
// i'm not sure what could trickle down past here, but it returns false :)
return false;
}

String comparison can be forced by a+'' == b+''. Number comparison by +a == +b. Boolean by !a == !b.

The following holds:
(A != B) === !(A==B)
(A==B) === (B==A) (except in the order of evaluation, which "can" be observed, but usually isn't)

Transitivity (if a==b and b==c then a==c) doesn't always hold due to coercion. A string object will match with a string literal with the same value, but not with another string object with the same value.

String comparison is simple, based on Unicode code point values. Strings that would canonically (after evaluation) match will not match using the equality comparison, unless they were the same string before evaluation.

I've written a tool which might help you in discovering the steps taken when coercion is applied. You can find it on jscoercion.qfox.nl :)