2

Assume that I have two literals: false and 1. If I invoke function toString() on both of them, I get:

false.toString() // false
1.toString()     // Uncaught SyntaxError: Unexpected token ILLEGAL

What does error happen in the second case and does not occur in the first one?

Downgoat
  • 13,771
  • 5
  • 46
  • 69
Finkelson
  • 2,921
  • 4
  • 31
  • 49
  • 1
    Put parentheses around the `1`. That should fix the error. – Noble Mushtak Aug 22 '15 at 22:55
  • It is not an option here. If I do that I will invoke function toString on string literal, and not on the number literal. – Finkelson Aug 22 '15 at 22:56
  • 1
    No, if you put parentheses around it, it will still be a number. `(1) === 1`. Putting parentheses doesn't change the value of anything; it's just that the JavaScript console thought the `.` was a decimal point, which is why they didn't expect `toString`. However, putting parentheses around the `1` makes the console parse the one as a number before the `.`, so the `.` now looks like a property/method getter instead of a decimal point because the console has finished parsing the number. – Noble Mushtak Aug 22 '15 at 23:00
  • ok, `typeof (1)` gives me a `number`. – Finkelson Aug 22 '15 at 23:04
  • 2
    Try `(1).toString()` or `1..toString()`... Both let the parser know that the `.` isn't a decimal point. – nnnnnn Aug 22 '15 at 23:04
  • It is some kind of JS trick, right? – Finkelson Aug 22 '15 at 23:04
  • I'm writing an answer to an answer to this question right now, which will hopefully explain things for you. – Noble Mushtak Aug 22 '15 at 23:06
  • possible duplicate of [Why don't number literals have access to Number methods?](http://stackoverflow.com/questions/4046342/why-dont-number-literals-have-access-to-number-methods) – user2864740 Aug 22 '15 at 23:23

2 Answers2

4

Using ..

Basically, 1 is a number so if it is immediately followed by a decimal it is taken as a floating point literal and expects to be followed by the fractional value (like 1.0).

1..toString() works because 1. is valid number literal and it knows to treat the next dot to access the object's properties. This means:

1.1.toString(); // Works
1.toString();   // "toString()" isn't a number so we get an error

Using []

var toString = "toString";

Now you can do:

1[toString]();

Using ()

You can use parenthesis for this. This works in a similar way to declaring a variable:

var a = 5;
a.toString();
(5).toString();

Why does this work?

It's because only when there is a . It will expect the following to be numbers.


Error

If you type in 1.toString() on your console (I'm using Safari). It should say:

At least one digit must occur after a decimal point

meaning it is expecting a digit.


What to do?

Because it can get annoying doing .. or adding extra parenthesis. You can use the String function to get around this:

String(1);
Downgoat
  • 13,771
  • 5
  • 46
  • 69
1

Actually, numbers are object literals. It's just that you need to put parentheses around the number so the console finishes parsing the number. This way, the . isn't mistaken for a decimal point. You can also put .s, one for a decimal point and one for the .toString():

//This outputs "2":
console.log((2).toString());
//So does this:
console.log(2..toString());
var hello = 2;
//So does this:
console.log(hello.toString());

For more on this parsing error, go check out @vihan's answer.

In JavaScript, there is a prototype for every type. For true and false, there is the Boolean prototype. For numbers like 1, there is the Number prototype. For strings like "Hi!", there is the String prototype. However, Booleans, numbers, and strings are all primitive objects, meaning they are immutable, meaning that you can't set properties on them like regular objects:

var hello = 2;
//hello is a Number object and can have properties and methods like .toString():
console.log(hello.toString());
//This doesn't work, however, because while hello is an object, it is immutable:
hello.hello = 2;
//This outputs undefined because the above didn't work:
console.log(hello.hello);

In contrast, arrays (from the Array prototype), functions (from the Function prototype), are mutable objects, so you can set properties on them just fine. Also, regular objects like {regular: true} descend from the Object prototype and are also mutable.

var arr = [1, 2];
//arr is mutable, so this works just fine and outputs 2:
arr.hello = 2;
console.log(arr.hello);

Thus, all literals in JavaScript are objects, but some are mutable while others are immutable. You can also make regularly mutable objects immutable with Object.freeze(), but making mutable objects immutable is even more complicated.

It should be noted that all of these prototypes -- Boolean, String, Number, Array, Function -- descend from Object. This is because all prototypes are objects themselves and must thus descend from Object. This is like how in Java where all classes descend from Object somehow. However, there is a way to get rid of descending from Object using __proto__, but that's EVEN MORE CONFUSING and it's probably not good to get into that if you're just getting into JavaScript.

I hope this explanation has helped you understand JavaScript better!

Noble Mushtak
  • 1,784
  • 10
  • 22
  • `prototype` and inheritance have nothing to do with this it's purely semantics. – Downgoat Aug 22 '15 at 23:17
  • His question was about understanding how JavaScript object literal works, not necessarily the parsing error. This gives him a more in-depth understanding of JavaScript objects instead of just telling him how to fix his example. – Noble Mushtak Aug 22 '15 at 23:19
  • @NobleMushtak Perhaps you could add both in your answer? In the future, people who visit this question will have no idea on how his problem was fixed. – Downgoat Aug 22 '15 at 23:23
  • 1
    @vihan No problem! Done! I added it at the top. – Noble Mushtak Aug 22 '15 at 23:25
  • 2
    *"numbers are object literals"* - Aren't they primitive literals? And then JS coerces them into the equivalent object if you call numeric methods on them. – nnnnnn Aug 22 '15 at 23:43
  • Yes, numbers, strings, and Booleans are primitive literals, but all values, including primitives, are objects in JavaScript. However, primitives are immutable and have a secret _[[PrimitiveValue]]_ property storing their value. However, other Web sites (like [Mozilla docs](https://developer.mozilla.org/en-US/docs/Glossary/Primitive)) will dispute this and say that primitives aren't objects. I think this is a dispute between JavaScript coders, but it remains that primitive values _clearly_ descend from prototypes such as `Number.prototype`, even if you don't wrap them in an "object wrapper." – Noble Mushtak Aug 23 '15 at 00:14