2

I run the following code in a browser console (FireFox and Chromium):

console.log('v' > 5);
console.log('v' < 5);

Both statements return false. It actually comes as no surprise in case of 'v' < 5, but why does 'v' > 5 return false? As far as I understand 5 gets converted to a string that is compared to 'v' lexicographically. Did I missed something, what coercion rule is applied here?

Andriy Simonov
  • 1,276
  • 1
  • 11
  • 19

1 Answers1

3

The coercion is in the other direction. 'v' is coerced to number, yielding NaN, which will make any comparison with another number return false.

See "What is the rationale for all comparisons returning false for IEEE754 NaN values?" on the behaviour of NaN

More details

From the EcmaScript specification:

In 12.9.3 Runtime Semantics: Evaluation the evaluation of both < and > operators is specified, with this important step:

  1. Let r be the result of performing Abstract Relational Comparison rval < lval with LeftFirst equal to false.

And,

  1. If r is undefined, return false. Otherwise, return r.

The 7.2.11 Abstract Relational Comparison starts out with:

The comparison x < y, where x and y are values, produces true, false, or undefined (which indicates that at least one operand is NaN).

NB: Note that undefined will lead to a false in the final evaluation, as stated in above quoted step 8 of section 12.9.3.

It is then required that after the primitive values have been taken from the operands, and they are not found to be both strings, they should be coerced to Number:

  1. If both px and py are Strings, then
    [...]
  2. Else
    a. Let nx be ToNumber(px).
    [...]
    c. Let ny be ToNumber(py).

Examples of Evaluated Expressions

Here is a series of comparisons, showing the different outcomes you can get:

function test(value, name) {
   if (arguments.length === 1) name = JSON.stringify(value);
   console.log(name + ' < 11.5 === ' + (value < 11.5) +  
       '. Number(' + name + ') = ', Number(value));
}
test('33');
test('3');
test('+11.9');     // coerces to number 11.9 (sign and decimal)
test('0xA');       // coerces to number 10 (hexadecimal notation)
test('');          // coerces to number 0
test('3v');        // invalid number
test('3e2');       // coerces to number 300 (exponent notation)
test('-Infinity'); // coerces to number -Infinity
test(new Date(), 'new Date()'); // coerces to number of milliseconds 
test({ valueOf: x => 2 }, '{ valueOf: x => 2 }'); // coerces to number 2
.as-console-wrapper { max-height: 100% !important; top: 0; }
Community
  • 1
  • 1
trincot
  • 317,000
  • 35
  • 244
  • 286
  • I don't think this is correct, comparison operators call valueOf() on both sides which would mean comparing 'v' and 5. The problem is greater/less than operators apply strict equality and the differing types means false is returned. – BenShelton Mar 11 '17 at 19:58
  • 1
    @BenShelton, try `"3" < 5` (true) , `"7" > 5` (true), and any variants of that. The relational operators are not strict. – trincot Mar 11 '17 at 20:04
  • @BenShelton According to http://www.ecma-international.org/ecma-262/6.0/index.html#sec-abstract-relational-comparison both operands are interpreted as numbers – le_m Mar 11 '17 at 20:13
  • @trincot Right you are. Turns out 'valueOf()' is used when comparing an object with a primitive, but strings are converted to numbers in these cases. Thanks for correcting me. – BenShelton Mar 11 '17 at 20:18
  • I added some quotations from the EcmaScript specs. – trincot Mar 11 '17 at 20:20
  • maybe you add some examples, like stringed numbers become numbers, some text become `NaN` and empty string becomes `0`. – Nina Scholz Mar 11 '17 at 20:53
  • @NinaScholz, Good idea. I added some examples. – trincot Mar 11 '17 at 22:02