How to create a string in JavaScript

How to create a string in JavaScript

When dealing with strings in JavaScript, the simplest and most effective approach is often just to use quotes. They allow you to define string literals without unnecessary complication. For instance, you can wrap text in either single quotes or double quotes, and both will work interchangeably. However, choosing one style and sticking with it throughout your code enhances readability.

let greeting = "Hello, World!";
let farewell = 'Goodbye, World!';

Quotes are great because they handle most cases you will encounter. If you need to include a quote within your string, you can escape it with a backslash.

let question = "He said, "What's going on?"";
let statement = 'It's a beautiful day!';

When using quotes, keep in mind that you can also utilize template literals, which are enclosed by backticks. Template literals offer you the flexibility of multiline strings and string interpolation.

let name = "Alice";
let welcomeMessage = Welcome, ${name}! 
We're glad to have you here.;

This can be incredibly useful when you want to build strings dynamically or format them in a more readable way. However, the need for template literals should not overshadow the simplicity of basic quotes. Most of the time, if you only need to define static strings, just use quotes.

Another key point to remember is that when you have to deal with JSON data, proper quoting becomes even more critical. A common mistake is forgetting to wrap the keys in double quotes when creating JSON objects. This can lead to syntax errors that are often hard to trace.

let jsonData = {
  "name": "John Doe",
  "age": 30,
  "isDeveloper": true
};

JavaScript’s flexibility allows you to create strings in various ways, but the best practice is to rely on quotes for your basic needs. Keeping it straightforward not only makes your code cleaner but also helps you avoid potential pitfalls that come with more complex approaches.

While quotes can handle most situations seamlessly, there are times when you’ll find them lacking. For instance, if you’re dealing with a large amount of dynamic data where quotes alone don’t suffice,

The modern approach for when quotes aren’t enough

you’ll need a more robust tool. This is where template literals, introduced in ES6, really shine. Before template literals, building complex strings was a nightmare of concatenation. You’d have a long chain of strings and variables joined by the + operator, and you’d have to manually insert newline characters like n. It was ugly, hard to read, and incredibly easy to make a mistake with a missing quote or plus sign.

let item = { name: "Widget", price: 25.50, quantity: 3 };
let orderDetails = "Order Details:n" +
  "Item: " + item.name + "n" +
  "Quantity: " + item.quantity + "n" +
  "Price per item: $" + item.price.toFixed(2) + "n" +
  "Total: $" + (item.price * item.quantity).toFixed(2);

Look at that mess. It’s barely readable. You have to mentally parse the entire expression to figure out what the final string will look like. It’s a recipe for bugs. A misplaced + or a forgotten space can break everything. Now, let’s see the same thing with a template literal.

let item = { name: "Widget", price: 25.50, quantity: 3 };
let orderDetails = Order Details:
Item: ${item.name}
Quantity: ${item.quantity}
Price per item: $${item.price.toFixed(2)}
Total: $${(item.price * item.quantity).toFixed(2)};

The difference is night and day. The code now looks almost exactly like the text it produces. The multiline nature is handled automatically, and variables or even entire expressions are embedded directly into the string using the ${...} syntax. This is not just a minor convenience; it’s a fundamental improvement in code clarity. You’re no longer writing instructions to build a string; you’re writing the string itself, with placeholders for the dynamic parts.

The power of template literals comes from the fact that you can put any valid JavaScript expression inside the curly braces. This isn’t limited to simple variables. You can perform calculations, call functions, or use ternary operators, and the result will be cleanly inserted into the string.

function calculateTax(price) {
    return price * 0.08;
}

let product = { name: "Super Gadget", basePrice: 99.99 };
let shippingCost = 10.00;

let invoice = `Product: ${product.name}
Price: $${product.basePrice}
Tax: $${calculateTax(product.basePrice).toFixed(2)}
Shipping: $${shippingCost.toFixed(2)}
--------------------
Total: $${(product.basePrice + calculateTax(product.basePrice) + shippingCost).toFixed(2)}
Status: ${product.basePrice > 50 ? 'Free Gift Included' : 'Standard Order'}`;

console.log(invoice);

This approach eliminates an entire class of common string-related errors. By making the code’s structure match the output’s structure, you reduce the cognitive load required to understand and maintain it. When you need to build a string from more than one or two simple parts, template literals are almost always the right choice. They are more readable, less error-prone, and more powerful than traditional string concatenation. While simple quotes are fine for simple, static strings, the moment things get dynamic, you should reach for backticks. This brings us to another important consideration: what happens when the data you’re trying to turn into a string isn’t a string to begin with? You might have numbers, booleans, objects, or even null and undefined values.

The safe way to convert anything to a string

So you have a value. It might be a number, a boolean, an object, or it might be the dreaded null or undefined. You need to display it to a user or write it to a log file, which means you need to turn it into a string. The JavaScript language, in its infinite and sometimes terrifying wisdom, gives you several ways to do this, and most of them are subtly wrong in ways that will bite you when you least expect it.

A common trick you’ll see is to concatenate the value with an empty string. It seems clever. It’s short, and it relies on JavaScript’s type coercion rules to do the work for you.

let num = 42;
let bool = false;
let obj = { id: 1 };
let arr = [1, 2, 3];

let numStr = "" + num;     // "42"
let boolStr = "" + bool;   // "false"
let objStr = "" + obj;     // "[object Object]"
let arrStr = "" + arr;     // "1,2,3"

This works, sort of. But look at the result for the object. You get the useless string "[object Object]", which tells you nothing about what’s actually inside. The array becomes a comma-separated list, which might be what you want, or it might not. The real problem with this approach, and with most of JavaScript’s implicit coercion, is that you’re relying on a complex set of rules that you probably haven’t memorized. It’s a landmine.

A slightly more explicit, and therefore slightly better, approach is to call the .toString() method that exists on most objects and primitives. This feels more intentional. You’re explicitly asking the value to represent itself as a string.

let num = 123;
let bool = true;

let numStr = num.toString();   // "123"
let boolStr = bool.toString(); // "true"

This seems fine until you get a value that doesn’t have a .toString() method. What values don’t have methods? The two troublemakers of the language: null and undefined. If your variable might hold one of these, and you call .toString() on it, your program will come to a screeching halt.

let value = null;
try {
  let str = value.toString(); // This will throw a TypeError
} catch (e) {
  console.error(e.name + ": " + e.message); // TypeError: Cannot read properties of null (reading 'toString')
}

This is a huge problem. You can’t have your logging function or your UI component crashing just because some data from an API call came back as null. You need a way that is guaranteed not to throw an error, no matter what the input is. That safe way is the global String() function.

When you call String() as a function (not as a constructor with new), it will safely convert any value to a string. It’s designed for this exact purpose. It follows a reliable algorithm that handles every data type, including the problematic ones.

String(123);          // "123"
String(false);        // "false"
String(null);         // "null"  <-- No error!
String(undefined);    // "undefined" <-- No error!
String([1, 2]);       // "1,2"
String({ a: 1 });     // "[object Object]"

This is the one you should use. It’s explicit, it’s readable, and most importantly, it’s safe. It will never throw a TypeError because the value is null or undefined. It reliably gives you a string representation. Notice that for a plain object, it still gives you "[object Object]". While String() is the safest way to avoid crashes, it doesn’t magically know how to serialize the *contents* of an object in a useful way. For that, you need a different tool.

The one way you should never, ever create a string

Now that we’ve established the safe way to convert any value to a string, let’s talk about the one way you should actively avoid. JavaScript, in its quest to be all things to all people, provides a String constructor. You can use it with the new keyword, just like you would create an instance of a custom class. This might seem like the “proper” object-oriented way to do things if you’re coming from a language like Java or C#.

It is not. It is a trap.

let primitiveStr = "This is a normal string.";
let objectStr = new String("This is a string object.");

console.log(typeof primitiveStr); // "string"
console.log(typeof objectStr);  // "object"

Look closely at that output. Using quotes gives you a primitive value of type string. Using new String() gives you a value of type object. It’s a string-like object, a “string wrapper object,” but it is fundamentally not the same thing as a primitive string. This single difference is the source of a whole category of confusing bugs that are difficult to track down.

The most common problem arises when you try to compare them. Modern JavaScript development strongly encourages using the strict equality operator (===) because it doesn’t perform any weird type coercion. It checks if both the type and the value are the same. And when you use it to compare a primitive string to a string object, you will get a result you probably didn’t expect.

let normalString = "hello";
let objectString = new String("hello");

if (normalString === objectString) {
  // This code will never run
  console.log("They are strictly equal.");
} else {
  console.log("They are NOT strictly equal."); // This is what you get
}

if (normalString == objectString) {
  // This code runs, adding to the confusion
  console.log("They are loosely equal.");
}

The strict comparison fails because the types are different (string vs object). This can lead to maddening situations where you’re looking at two variables in the debugger that both seem to contain the exact same text, yet your logic which depends on them being equal is failing. You might have a function that returns new String("success") and you’re checking if the result === "success". It will always be false.

There is literally no advantage to using the new String() constructor. Any method you might want to use, like .toUpperCase() or .slice(), is available directly on primitive strings. JavaScript automatically and temporarily wraps the primitive in an object when you call a method on it, a process called “auto-boxing.” You get all the convenience of the methods without the persistent, problematic object wrapper. So, to be clear: using the String() function for type conversion is good and safe. Using the new String() constructor is always a mistake.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *