Overview of String Conversion in JavaScript

When I started working with JavaScript many years ago, I learned that to convert a value to a string, I could use value.toString().
This method worked well and was sufficient to complete the tasks I had at the time. However, as I progressed and started collaborating with other developers, I discovered additional ways to convert a value to a string. Here’s the full list:
value.toString()value + ''or`${value}`String(value)JSON.stringify()
I was surprised to learn that each of these approaches works slightly differently, and I think experienced developers should be aware of these differences. In this article, we’ll dive into how each method behaves so you can choose the one that best suits your needs.
Option #1: value.toString()
value.toString() is an explicit conversion to a string because you are directly calling a method to perform the conversion. This option works only if the value is an object that has a toString() method; otherwise, it will throw a TypeError. Here are some examples to illustrate the difference:
// The variables below are objects that have toString() method
// Primitive data types such as number and boolean are also objects
const a = 50;
const b = true;
const c = [1, 2, 3];
const d = { name: "Andrew" };
console.log(a.toString()); // => "50"
console.log(b.toString()); // => "true"
console.log(c.toString()); // => "1, 2, 3"
console.log(d.toString()); // => "[object Object]"
// The variables below are not objects and do not have toString()
// method. Calling .toString() on them will result in TypeError
const e = null;
const f = undefined;
console.log(e.toString());
// TypeError: Cannot read properties of null (reading 'toString')
console.log(f.toString());
// TypeError: Cannot read properties of undefined (reading 'toString')
Good news: all standard objects in JavaScript - such as Number, Array, and Function have the toString() method implemented. It is used whenever an object needs to be represented as text (for example, in HTML) or whenever an object is implicitly converted to a string.
The important thing to remember is that calling value.toString() on null or undefined will throw a TypeError. This happens because these values are not objects and therefore do not have a toString() method.
You can also override the toString() method for your own objects or even for existing built-in objects. However, modifying built-in prototypes is generally discouraged, as it can cause unexpected behavior in other parts of your code or in third-party libraries.
Option #2: String(value)
String(value) is another explicit way to convert a value to a string using the String constructor. However, it works a bit differently than value.toString(). When you call String(value) on null or undefined, it will return a string with "null" or "undefined" respectively. And this is the most important difference to remember.
const a = 50;
const b = true;
const c = [1, 2, 3];
const d = { name: "Andrew" };
console.log(String(a)); // => "50"
console.log(String(b)); // => "true"
console.log(String(c)); // => "1, 2, 3"
console.log(String(d)); // => "[object Object]"
// Note that we do not get a TypeError
// when calling String() on null or undefined
console.log(String(null)); // => "null"
console.log(String(undefined)); // => "undefined'
One important thing to note: since String is a constructor, it is possible to call it with the new keyword - new String(value). You should rarely use it this way.
When String is called as a function, it coerces the parameter to a string primitive. However, when String is called as a constructor (with new), it creates a String object, which is not a primitive. This produces different results:
const a = new String("Hello from 2023!");
const b = String("Hello from 2023!");
console.log(a); // => String {"Hello, 2023!"}
console.log(b); // => "Hello, 2023!"
console.log(a === 'Hello from 2023!'); // => false
console.log(b === 'Hello from 2023!'); // => true
console.log(a instanceof String); // => true
console.log(b instanceof String); // => false
console.log(typeof a); // => "object"
console.log(typeof b); // => "string"
Option #3: value + "" or `${value}`
When you concatenate a string with any other value, JavaScript will automatically convert the other value to a string. This is an implicit way to convert a value to a string because the + operator is not specifically designed for string conversion. Instead, it is a general-purpose operator that can be used for addition or string concatenation, depending on the types of the operands.
When you try to convert null or undefined to string, it will not result in TypeError:
const a = null;
const b = undefined;
console.log(a + ""); // => "null"
console.log(`${a}`); // => "null"
console.log(b + ""); // => "undefined"
console.log(`${b}`); // => "undefined"
However, I am not a big fan of using this method because it involves implicit string conversion and it can be difficult for other developers unfamiliar with JavaScript to understand how the code works at the first glance.
Whenever possible, I prefer to use String(value) or JSON.stringify(value) (comes next in the article), which are explicit conversions that do not throw a TypeError when calling on null or undefined.
Option #4: JSON.stringify(value)
This method is particularly useful for converting objects and arrays to JSON strings because it can handle nested objects and arrays. Remember what we got when we called value.toString() or String(value) on array or objects?
const a = [1, 2, 3];
const b = { name: "Andrew" };
console.log(a.toString()); // => "1,2,3"
console.log(String(a)); // => "1,2,3"
console.log(b.toString()); // => "[object Object]"
console.log(String(b)); // => "[object Object]"
This is not the case with JSON.stringify(), consider this example:
const a = [1, 2, 3];
const b = { name: "Andrew" };
console.log(JSON.stringify(a)); // => "[1,2,3]"
console.log(JSON.stringify(b)); // => '{"name":"Andrew"}'
As you can see, when we call JSON.stringify() on arrays, we get a valid JSON array as a string, and when we call JSON.stringify() on objects, we get a valid JSON object as a string. This also works when we have nested arrays or objects:
const a = [ ['a', 'b'], 5 ];
const b = { name: "Andrew", skills: [ "JavaScript", "TypeScript" ] };
console.log(JSON.stringify(a)); // => '[["a","b"],5]'
console.log(JSON.stringify(b)); // => '{"name":"Andrew","skills":["JavaScript","TypeScript"]}'
Calling JSON.stringify() on null or undefined works the same as with String():
console.log(JSON.stringify(null)); // => "null"
console.log(JSON.stringify(undefined)); // => "undefined"
JSON.stringify() is a more complex method than the previous ones, and in addition to the value to be converted to a string, it also takes two optional parameters: placeholder and space. Refer to the MDN Docs if you want to learn more.
Converting Dates to String
When we try to convert JavaScript dates to a string, the first three options work the same, while JSON.stringify() gives a different result. Consider this example:
const date = new Date(2023, 0, 1, 10, 0, 0);
console.log(String(date));
// => "Sun Jan 01 2023 10:00:00 GMT-0500 (Eastern Standard Time)"
console.log(date.toString());
// => "Sun Jan 01 2023 10:00:00 GMT-0500 (Eastern Standard Time)"
console.log(date + "");
// => "Sun Jan 01 2023 10:00:00 GMT-0500 (Eastern Standard Time)"
console.log(JSON.stringify(date));
// => '"2023-01-01T15:00:00.000Z"'
In this case, JSON.stringify() returns the date in ISO simplified extended format (ISO 8601). This is because the date object we pass to JSON.stringify() method implements the toJSON() method which returns a string (the same as date.toISOString()).
Always Consider Performance
Now, you may be tempted to use JSON.stringify() all the time as it offers the most complete conversion. However, you should know that String() is likely to be faster than JSON.stringify() because it is a simpler operation that does not involve parsing or formatting the input value as a JSON string.
String() simply converts the input value to a string using a simple set of rules, as we discussed earlier. This operation is generally fast and efficient, especially for primitive values.
On the other hand, JSON.stringify() is a more complex operation that involves parsing the input value and generating a JSON string that represents the object in a standardized format. Depending on the size and complexity of the input value, this operation can be relatively slow and resource intensive.
Even though the performance difference may not be significant, I strongly recommend choosing the right method wisely: if you do not need a JSON string in a standardized format, use String(value) or value.toString(), otherwise, use JSON. stringify(value).
The end. I hope you found this information helpful, stay tuned for more content! :)



