16

I'm reading through Douglas Crockford's JavaScript: The Good Parts, and I'm at the point where he defines a fade function. Part of this code boils down to this:

var level = 1;
var hex = level.toString(16);

So I run this in my browser's console to see what I get....

var level = 1;
level.toString(16);

Hey, it returns "1"... Fabuloso! Wunderbar!

Then to be cheeky, I try this to see what I get...

1.toString(16);

And I get

SyntaxError: Unexpected token ILLEGAL

What the what? If level is a variable equal to 1, and running this method on level works fine, then why doesn't running this method on the actual number 1 work? I tried a similar experiment with the toPrecision() method and that worked fine in both cases. What's the issue here? Is this another one of those inherent flaws in the JavaScript implementation, or am I missing something? I am testing in Google Chrome.

Related: Stack Overflow question Why don't number literals have access to Number methods?.

Community
  • 1
  • 1
Bob Ralian
  • 1,949
  • 1
  • 20
  • 29
  • Related: [What's wrong with this code? I am not able to extend the Number object](http://stackoverflow.com/q/6833521/), [What does `1..something` mean in JavaScript?](http://stackoverflow.com/q/2300197/) – Christian C. Salvadó Jul 28 '11 at 04:32

3 Answers3

20

It's just a language grammar limitation.

Since 1. is a legal literal number (and 1.t is not) the tokeniser will split this into the following tokens:

1.
toString
(
)

And that's an illegal sequence of tokens. It's object method, instead of object . method.

In the working versions in @Joey's answer, the braces prevent the tokenizer from treating the dot as part of the number literal instead of as a separate token, as does writing:

1.0.toString()

or

1..toString()

since the tokenizer knows that the second dot must be a token on its own, and not part of the number literal.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • Aha! That makes sense. Winner, winner, chicken dinner. – Bob Ralian Jul 28 '11 at 03:53
  • However, the parser *should* know that identifiers that begin with a number are illegal, and therefore it should be evaluated as a number. Perhaps a limitation? – Peter Jul 28 '11 at 04:03
  • @peter it's nothing to do with identifiers. The tokenizer will grab the first dot as part of a "number token", which means it's no longer available to be a token in its own right. – Alnitak Jul 28 '11 at 04:04
  • I think the parser knows it's a number... it just doesn't know where the number ends, as Alnitak explains. Both 1 and 1. are valid, equivalent numbers in javascript. So the parser is not recognizing the dot as indicating a method, but rather as a decimal with invalid characters after it. I get the same error if I just put 1.bork into the console. But by having two decimal points, js knows the second dot means a method is coming next. So using my own example I get a valid response when I try 3.14159.toString(16) because there are two dots. – Bob Ralian Jul 28 '11 at 04:10
  • Good grief!! An intelligent conversation about parsers and tokenisers on SO! What will they think of next - quoting the spec?? :-o – RobG Jul 28 '11 at 04:33
  • Thanks @Bob, that's a good explanation. Alnitak, I was mostly alluding to the fact that the parser was not able to properly decompose the expression. I would have thought that the lexer would force the only possible match? – Peter Jul 28 '11 at 04:43
  • @Peter it's too late for the parser by then - the lexer already made the decision to consume the dot as part of the number literal. – Alnitak Jul 28 '11 at 13:31
4

You need 1..toString or (1).toString to get the number literal

Joe
  • 80,724
  • 18
  • 127
  • 145
  • Ok, that gives me the how, but not the why. Why does 3.14159.toPrecision(3) work fine, but 1.toString(16) give me an error? They're both methods on the number object. – Bob Ralian Jul 28 '11 at 03:49
-2

level is a variable (and thus an object).

1 is a literal. They are not objects and the interpreter thinks about them completely differently.

http://www.cs.brown.edu/courses/bridge/1998/res/javascript/javascript-tutorial.html#4

mbarnes
  • 455
  • 2
  • 7
  • numbers are objects, and number methods can act upon them. Alnitak hit on the right answer by explaining that the dot is ambiguous to the javascript parser as either a decimal point or as indicating a property of that object. Or maybe not ambiguous, as javascript unambiguously sees the first dot as a decimal point and not an indicator of an object property. But if you try 1..toString(16), we're all in coolsville. :-) – Bob Ralian Jul 28 '11 at 04:21
  • @BobRalian Actually numbers are not objects - they're primitive value types - they're just readily boxed to `Number` objects – Benjamin Gruenbaum Sep 01 '13 at 09:53
  • Or in JavaScript: _coerced_ into `Number` objects. – Sebastian Simon Jan 17 '19 at 13:42