Reputation: 1321
I am trying to understand the mystery of comparing functions:
let a=function(){}
let b=function(){}
console.log(a==b) //false
console.log(a===b) //false
console.log(a<b) //false
console.log(a>b) //false
console.log(a<=b) //true !?!
console.log(a>=b) //true !?!
console.log( (+a) < (+b) ) //false
console.log( (+a) > (+b) ) //false
console.log( (+a) <= (+b) ) //false
console.log( (+a) >= (+b) ) //false
In ECMAscript the <= operator is described:
RelationalExpression:RelationalExpression<=ShiftExpression
- Let lref be the result of evaluating RelationalExpression.
- Let lval be ? GetValue(lref).
- Let rref be the result of evaluating ShiftExpression.
- Let rval be ? GetValue(rref).
- Let r be the result of performing Abstract Relational Comparison rval < lval with LeftFirst equal to false.
- ReturnIfAbrupt(r).
- If r is true or undefined, return false. Otherwise, return true.
The Abstract Relational Comparison seems to have special cases for strings and BigInts but I think everything else should be converting to numbers. So I would expect the second set of comparisons to be equivalent to the first and yet it's not. What am I missing?
Upvotes: 4
Views: 69
Reputation: 141829
The Abstract Relational Comparison calls ToPrimitive on the arguments with a hint of 'number'
. That then calls OrdinaryToPrimitive again with a hint of 'number'
.
The hint here is really just a hint; it is not required that the routine returns that type. The hint of 'number'
just causes OrdinaryToPrimitive to try calling valueOf
before toString
, but it will still end up calling toString
if valueOf
does not return a primitive.
If you provide a valueOf implementation that returns a primitive it will be used for the comparison:
let a=function(){}
let b=function(){}
a.valueOf = () => 1;
b.valueOf = () => 0;
console.log( a <= b );
console.log( b <= a );
By default valueOf for a function returns the function itself, which is not a primitive, so toString is called instead and the functions are compared as strings.
Upvotes: 6