What are strings?

At the core,

A string is a sequence of textual characters.

These textual characters can be alphabets, digits, emoticons, special characters (such as newlines, tabs, carriage returns), characters from other languages, etc.

Each character in a string sits at a given position referred to as its index.

Indexes begin at 0. The first character is at index 0, the second is at index 1, the third is at 2, and so on and so forth.

The total number of characters in a string is referred to as its length. Each character in a string sits at a given position referred to as its length.

Creating strings

In JavaScript, a string could be created using single quotes ('') or double quotes (""):

Such strings are called string literals.

Consider the snippet below where we demonstrate both these ways to create a string:

'I am a string in JavaScript.'
'I am a string in JavaScript.'
"So am I."
'So am I.'

Practically, there is no difference between creating strings using either way. There is just one use case of each of these:

Double quotes are handy when we want to have single quotes in the string itself, and similarly single quotes are handy when we want to have double quotes in the string itself.

Consider the following code:

var s = 'He said: "I love you"';
console.log(s);
He said. "I love you"

Here, the string s has double quotes (") inside it, and therefore couldn't be denoted using double quotes since that would lead to a character conflict. Rather, it's denoted using single quotes.

A similar example is illustrated below:

var s = "What's up buddy?";
console.log(s);
What's up buddy?

Here, the string s contains a single quote (') inside it, and therefore couldn't be denoted using the same single quotes. Rather, it's denoted using double quotes.

Now one case that is still not covered is when we need both double and single quotes inside the string itself. As the reader could verify ,we couldn't use single or double quotes to denote such a string, since either would come in conflict with a similar character inside the string.

To solve such a case, we could either escape the conflicting quote, or use template literals.

Both of these would be covered in the sections following the one below.

Concatenation

One of the most fundamental concepts to strings in every programming language is that of concatenation.

So what is it?

Concatenation is the joining of two or more strings together to produce a single string.

In short, concatenation is just a fancy word for joining strings together.

In JavaScript, we could use the concatenation operator (+) to concatenate two strings together.

Note that this is the same operator used to add two numbers together as well. This leads us to an interesting question...

How does JavaScript distinguish between numeric addition and string concatenation when it encounters the + operator?

Here's how...

If any of the operands of the + operator is a string (or has a string representation), JavaScript performs string concatenation on the given operands. Otherwise it performs normal numeric addition.

Consider the snippet below:

// numeric addition
// neither operand is a string
console.log(10 + 20);

// string concatenation
// left operand is a string
console.log('20' + 10);

// string concatenation
// right operand is a string
console.log(10 + '20');

// string concatenation
// both operands are strings
console.log('10' + '20');
30
2010
1020
1020

As can be seen here, only the first expression involving the + operator is a numeric addition, since both the given operands are numbers.

The rest are all string concatenation expressions, as they have at least one string operand involved. The number in these expressions (if there is one) is converted into a string and then concatenated.

Therefore all of the following are examples of concatenation:

// again + operator in concatenation context
console.log(10 + "Hello"); // returns 10Hello
console.log("Hello" + 10 + "Hello") // returns Hello10Hello
console.log("Hello" + 10 + 10 + "Hello") // returns Hello1010Hello
In the above example "Hello" + 10 + 10 + "Hello" would return "Hello1010Hello" and not "Hello20Hello" because interpretation is done from left to right.

Therefore this is the flow for "Hello" + 10 + 10 + "Hello":
  1. First "Hello" + 10 is performed and this gives the string "Hello10"
  2. Second "Hello10" + 10 is performed which gives the string "Hello1010"
  3. Lastly "Hello1010" + "Hello" is perfomed which gives the string "Hello1010Hello"

Escaping characters

Let's come back to the problem of putting both single and double quotes inside a string.

As stated before, we could create such a string using either of the ways shown above — using single quotes ('') or double quotes ("").

As you could see in both the cases above, we get an error thrown by the interpreter. This confirms that the string couldn't be created in the way it is currently being created.

Now what?

Well, we could escape the conflicting character in the string.

Escaping a character in a string means to precede it with backslash character (\).

An escaped character is parsed specially by the interpreter.

In the case of a quote character (single or double) following a backslash (\), the interpreter parses it literally as a character inside the string, even if it is the same as the character denoting the string.

Consider the string below:

var s = 'He said: "It\'s impossible."';
console.log(s);
He said: "It's impossible."

Here we denote the string using single quotes, and then use both single and double quotes inside the string. For the single quote, we precede it with a backslash (\). This escapes the following ' character so that it is not interpreted as the end of the string.

Easy?

Let's try to denote this string using double quotes:

var s = "He said: \"It's impossible.\"";
console.log(s);
He said: "It's impossible."

Simple, as before.

Although backslashes can solve such cases of character-conflict problems, they complicate string expressions.

Another way is to use template literals. The following section expands on this idea.

Template literals

The ECMAScript 2015 spec introduced something called template literals into JavaScript. They represent an extremely simple, yet powerful idea.

Let's discuss on it.

A template literal, denoted using a pair of backticks (``), creates a string that could span multiple lines and contain JavaScript code.

OK, so this is a long definition! Let's break it down into simple pieces...

A template literal is denoted using a pair of backtick characters (``).

Shown below are a couple of template literals:

`Hello World!`
"Hello World!"
`What's up?`
"What's up?"
`He said: "It's impossible."`
"He said: \"It's impossible.\""

Notice the last template string in this snippet. It uses both single and double quotes in the text without any backslash characters.

This is one application of template strings — to create strings that contain both single (') and double quotes ("), without having to manually escape the conflicting characters.

Secondly, a template literal could span multiple lines, unlike strings created using single ('') or double quotes ("").

Consider the code below:

var s = `This is line 1,
and this is line 2.`;

console.log(s);
This is line 1,
and this is line 2.

We create a variable s and then assign a template string to it. Notice the new lines in this template string. These translate to actual newline characters in the final string.

As a rule of thumb, remember that:

The way a template literal is laid out in the source code is the same way it gets displayed when output.

If you put newlines in a template string, they would translate to actual newlines (i.e. the special character \n) in the final string. This is the reason why sometimes template literals are also called multi-line strings.

Lastly, a template literal could contains JavaScript code — or strictly speaking, valid JavaScript expressions.

There is a special notation to represent a piece of code inside a template literal, shown as follows:

`${expression}`

We begin with the $ character, followed by a pair of curly braces {}. Inside these, we put the desired expression.

This whole ${expression} notation is replaced by the return value of expression in the final string, after the interpreter parses the template literal.

An example follows:

var lang = 'JavaScript';
var s = `You are learning ${lang}.`;

console.log(s);
You are learning JavaScript.

Here, the template string contains ${lang}, which simply means that this notation would be replaced by the value of the variable lang. lang holds the string 'JavaScript', likewise s becomes 'You are learning JavaScript.'.

Easy?

Why are they called 'template literals'?

The word 'template' comes from the fact that such a string denotes a template expression, that is replaced by actual stuff when parsed.

For instance, consider the string below:

`${name} is ${age} years old.`

This string is a template string in that it defines the general form of the piece of text stored in the string. ${name} is replaced by the name of an actual person, and ${age} is replaced by that person's age.

A template string is parsed by the JavaScript engine at runtime and any ${} occurrences replaced by the return values of the respective expressions.

Talking about the word 'literal', it comes from the fact that `` is a string literal — exact representation of a string in source code, just like the string literals '' and "".

Hence, the name 'template literals'.

Immutability

Recall from the chapter JavaScript Data Types, that all primitives in the language are immutable in nature. That is, once created, they couldn't be modified.

Any modifications desired to be made to a primitive gets performed on a copy of the primitive — not on the actual value.

Strings as we know are primitives as well and are configured to be immutable.

Technically, even string objects are immutable in nature. We'll see what this means in the last section of this chapter.

This could be seen in the code below:

var s = 'Good';
s[0] = 'F';

console.log(s);
Good

As can be seen, the log made in the console is exactly the same string s created at the start of this program. The statement s[0] = 'F' is simply ignored.

The reason is because strings are immutable — we can't mutate them.

If strings were mutable in JavaScript, this code would have logged 'Food' in the console instead of 'Good'.

The String constructor

As we saw in the chapter, a string could be created using the String() constructor.

We start with the new keyword followed by the String() function's invocation. Inside the parentheses, we specify an optional value which would be coerced into a string and set as the current object's value.

The String() constructor throws back a String object — NOT a string primitive.

This object has multiple properties and methods available on it, such as length, toUpperCase() toLowerCase(), and so on and so forth.

Below we create a String object and convert it into all uppercase characters.

What is the difference b/w a string primitive and object.

One of the most confusing things for newbie JavaScript devs is that most of the primitive values such as number, strings, and Booleans have equivalent object values in the language, so what should one use — primitives or objects.

For instance, consider the code below:

Here we have a string s that is output to the document.

The same code could be rewritten as follows:

This time we have a string object s that is output to the document.

The question is which of these to use?

Well, we discussed the answer to this in detail in the chapter, but from the perspective of numbers. Essentially the idea is the same for all values. Let's go over it one more time for the case of strings.

The purpose of these constructor objects is to box primitive values.

When we create a string primitive and access a property on it, JavaScript automatically converts the primitive into the equivalent object behind the scenes, access the property on that object, and finally removes it.

Let's see how this works.

Consider the code below:

Here we create a string primitive and then access the length property on it. This length property doesn't exist on s, since it is a primitive value.

What JavaScript does at this point before accessing the length property is that it boxes the primitive s into an object.

Shown below is a rough depiction of what happens behind the scenes:

var s = 'Hello';
var _s = new String(s);
console.log(s.length);
_s = null;

JavaScript automatically creates a new variable and assigns it a String object that is constructed using the existing value s. After this, it performs all the operations performed on s in the source code and in the end, sets _s to null.

This has the consequence of the string object being garbage-collected. Everything works under the hood, and we feel as if we accessed a property on a primitive.

How clever is JavaScript!

So to boil it down, the use of new String() is limited to the JavaScript engine — we don't need to use these to create the respective values in our code snippets.

In fact, if we were to do so, we would be complicating our code visually and memory-wise as well.

Visually because so many constructor expressions could unnecessarily elongate the source code and memory-wise because we are creating objects and objects, and only objects, in memory that store a lot of overhead in addition to the actual value.

This doesn't happen with primitives — they just store the value; no overheads.

In addition to this, many operations such as typeof wouldn't work as expected on object values such as new String().

In short, it's a mess to use constructor functions explicitly to create strings, numbers or Booleans.

Woah, this was some solid theory under discussion!

One extremely crucial thing to remember is that String() is different from new String(). The former coerces a given value into a string primitive, whereas the latter converts a given value into the string object.

This means that you could use String() (or Number(), or Boolean()) to convert a given value into a string (or number, or Boolean) primitive.

When the new keyword comes into the game, then it's a different story, as we've discussed in detail above.

In the end

Understanding these concepts are imperative before you move on to explore string properties and methods in the next chapter. If you are unable to understand any one of them, consider reviewing the sections above and see if you understand it on reading them twice or even more times.

Experiment around with these concepts in the console, and once you are well off with them consider moving on to the next chapter. Keep learning and progressing!