6

I want to get a string represention of any object or value in JavaScript. I did a couple of experiments.

> var a = document.createTextNode('foo'); a
  "foo"
> var a = document.createTextNode('foo'); a.toString()
  "[object Text]"
> var a = 1; a.toString()
  "1"
> (1).toString()
  "1"
> 1.toString()
  SyntaxError: Unexpected token ILLEGAL

I have the following questions:

  1. Why does 1.toString() fail?
  2. Will the following function return me a string representation of every possible JavaScript object, value or literal? Function: function str(a) {return a.toString()}
  3. Is there any other alternative to the function str I have written in the previous point?
Lone Learner
  • 18,088
  • 20
  • 102
  • 200

3 Answers3

6

1). Why does 1.toString() fail?

The JavaScript parser only uses a 1 character lookahead and can't determine if that's 1.0 or 1.toString(). You can use 1..toString() to get around that.

2). Will the following function return me a string representation of every possible JavaScript object, value or literal? Function: function str(a) {return a.toString()}

Any literal will be converted to a temporary object in order to have its toString() called. If the object has its own toString() defined, it will be called. Otherwise, it will use Object.prototype.toString() (having gone up the prototype chain) for almost all cases (the other case is an object with a null prototype).

3). Is there any other alternative to the function str I have written in the previous point?

Yes. You can invoke the toString() implicitly by concatenating an empty string, e.g. 1 + "". You can also use the String constructor, e.g. String(value) (thanks T.J. Crowder). The advantages of these other ones is no exception will be thrown if you attempt to call toString() on null or undefined.

However, these tricks will convert null and undefined to their string equivalents (almost never what you want). One dirty trick is to put the value in a literal array, e.g. [value] and then call toString() on it. This will actually invoke join(","), but seeing as it only has one member, the comma will never become part of the string.

The real power of doing this is that null and undefined will just become an empty string. If that's OK for your program, then it can be useful. Keep in mind to comment this solution as it's not immediately obvious what this code is doing. Alternatively, check value == null which will detect null and undefined and handle it appropriately.

However, if you're wanting a string in order to classify a value, you can get the type's [[Class]] like so...

var getInternalClass = function(value) {
    return Object.prototype.toString.call(value).slice(8, -1); 
};

This will invoke the Object's toString() and set the ThisBinding to the value provided as the argument. This is the only way to expose an object's internal [[Class]]. The advantage of this (over typeof, for example) is that primitives and objects will always return the same value (with the primitives being converted to temporary objects, boxed by the call() context in non-strict mode).

alex
  • 479,566
  • 201
  • 878
  • 984
  • Or by using the `String` constructor as a converter: `String(1)` returns `"1"`. – T.J. Crowder Sep 22 '13 at 09:54
  • Indeed. It's probably worth pointing out to the OP that either your concatenation or using `String` will avoid throwing an exception where `a.toString()` will throw, if `a` is `null` or `undefined`. – T.J. Crowder Sep 22 '13 at 09:56
  • @alex Would you please elaborate the answer to 1. Why should 1 character lookahead be a problem? JS parser first reads `1`. Then it reads `1.`. It doesn't know if it's `1.0` coming up or `1.toString()` coming up. Now it reads `1.t` and it would know that it is not `1.0` but a function call on `1`. what's the problem here? – Lone Learner Sep 22 '13 at 10:05
  • @LoneLearner Been a while since I looked at tokenising stuff so I'm not sure now. However, I found [this comment](https://github.com/BonsaiDen/JavaScript-Garden/issues/84#issuecomment-1452557) which seems to make the same claim. If you can wait for me to look back into it, I can come back and edit the answer (but it will be months). :) – alex Sep 22 '13 at 10:14
  • Which one of these has the best performance? Excluding `.toString()` of course. – benjaminz Jan 19 '17 at 16:18
  • @benjaminz Not sure, but it's probably unlikely to become the bottleneck in a real app. – alex Jan 19 '17 at 16:19
1

for 1.toString(), you need to do:

1 .toString() //add space before dot (.) to avoid taking it as decimal

shortest way (alternative to function str ) to convert to string is:

var str = str + '';
Sudhir Bastakoti
  • 99,167
  • 15
  • 158
  • 162
  • Instead of doing `str = str + ''` one can also do `str = String(str)` (Note the missing `new` operator! `String` is also a function!) which is somewhat easier to read / more ideomatic. – ntninja Sep 13 '18 at 19:11
0

Your str(a) function is correct but it will call the default implementation of toString() inherited from Object. So yes, your function will give you string representation of every JS object but not in way you want it. You need to override it.

var o = new Object();
o.toString();           // returns [object Object]

See here for reference and overriding: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString

dejavu
  • 3,236
  • 7
  • 35
  • 60
  • Could you please elaborate by what you mean by "not in the way you want it"? I want whatever string is returned by the `toString()` function. Why do I have to override `toString()`? Is every object and literal in JavaScript provided with a default implementation of `toString()`? If yes, that's all I need. – Lone Learner Sep 22 '13 at 10:09
  • @LoneLearner, if you need the default implementation of every object and literal then this will work. But if you want customized value, then you need to override it. – dejavu Sep 22 '13 at 10:58