I have two code snippets which are using tagged template feature of template literals
Code one
function myTaggedLiteral(strings, value, value2) {
console.log(strings, value, value2);
}
let someText = 'Neat';
myTaggedLiteral `test ${someText} ${2 + 3} test2`;
In this case it will log
[
"test ",
" ",
" test2"
] Neat 5
This another example is from mdn
var person = 'Mike';
var age = 28;
function myTag(strings, personExp, ageExp) {
console.log(strings, personExp, ageExp)
// some other code
}
var output = myTag `That ${ person } is a ${ age }`;
This will log
[
"That ",
" is a ",
""
] Mike 28
So in first log there is an empty string "" after test , my understanding was this of the template expression ${someText} ${2 + 3} but in the second log there is no "" after That , although both of function is called in almost same structure of parameters.
Will really appreciate if someone helps me to understand why there is an empty string after test in the first log.
Secondly if I tweak the first program
function myTaggedLiteral(strings, value, value2) {
console.log(strings);
}
let someText = 'Neat';
myTaggedLiteral `test test6 test3 ${someText} ${2 + 3}`;
and this will log
[
"test test6 test3 ",
" ",
""
]
As per mdn
The first argument of a tag function contains an array of string
values.
If that is so then why it is outputting the first value as "test test6 test3 " instead of "test","test6","test3"?
Think of the strings parameter like the result of a String.prototype.split() where the separator is any placeholder, aka
... indicated by the dollar sign and curly braces (${expression}).
Here's an example
let templateString = 'test test6 test3 ${someText} ${2 + 3}'
let strings = templateString.split(/\$\{.*?}/) // regex for a placeholder
console.log(strings)
From the documentation...
If separator appears at the beginning or end of the string, or both, the array begins, ends, or both begins and ends, respectively, with an empty string
That is why, if any placeholders appear at the boundaries of your string, you will get empty strings in the resulting array.
In this you can always be sure that strings will have one more entry than there are placeholder expressions. Creating the resulting string will always involve (ignoring any extra transformations you might want to do)...
strings[0] + arg[0] +
strings[1] + arg[1] +
...
strings[n] + arg[n] + strings[n+1]
where n is the number of placeholders.
Related
Assume i have a string
var str = " 1, 'hello' "
I'm trying to give a function the above values found in str but as integer and string- not as one string-
for example myFunc(1,'hello')
how can i achieve that
i tried using eval(str),
but I'm getting invalid token ,
How can i solve this?
The following should work with any number of arguments.
function foo(num, str) {
console.log(num, str);
}
const input = "1, 'hel,lo'";
const args = JSON.parse('[' + input.replace(/'/g, '"') + ']');
foo(...args);
You've almost got the right idea with eval(str) however, that isn't the thing you actually want to evaluate. If you do use eval(str), it is the same as saying eval(" 1, 'hello' ")
However, what you really want to do is:
eval("func(1, 'hello world')).
To do this you can do:
eval(func.name + '(' + str.trim() + ')');
Here we have:
func.name: The name of the function to call. You can of course hard code this. (ie just write "func(" + ...)
str.trim(): The arguments you want to pass into the given function. Here I also used .trim() to remove any additional whitespace around the string.
Take a look at the snippet below. Here I have basically written out the above line of code, however, I have used some intermediate variables to help spell out how exactly this works:
function func(myNum, myStr) {
console.log(myNum*2, myStr);
}
let str = " 1, 'hello, world'";
// Build the components for the eval:
let fncName = func.name;
let args = str.trim();
let fncStr = fncName + '(' + args + ')';
eval(fncStr);
Alternatively, if you only wish to pass in two arguments you can use .split(',') on your string to split the string based on the comma character ,.
Using split on " 1, 'hello' " will give you an array such as this one a:
let a = [" 1", "'hello'"];
Then cast your string to an integer and remove the additional quotes around your string by using .replace(/'/g, ''); (replace all ' quotes with nothing ''):
let numb = +a[0].trim(); // Get the number (convert it to integer using +)
let str = a[1].trim().replace(/'/g, ''); // get the string remove whitespace and ' around it using trim() and replace()
Now you can call your function using these two variables:
func(numb, str);
function func(myNum, myStr) {
console.log('The number times 2 is:', myNum*2, "My string is:", myStr);
}
let arguments = " 1, 'hello' ";
let arr = arguments.split(',');
let numb = +arr[0].trim(); // Argument 1
let str = arr[1].trim().replace(/'/g, ''); // Argument 2
func(numb, str);
I have the following code for ECMAScript 6 template literals:
let person = {name: 'John Smith'};
let tpl = `My name is ${person.name}.`;
let MyVar = "My name is " + person.name + ".";
console.log("template literal= " + tpl);
console.log("my variable = " + MyVar);
The output is as follows:
template literal= My name is John Smith.
my variable = My name is John Smith.
This is the fiddle.
I tried searching for the exact difference, but I couldn't find it,
What is the difference between the following two statements?
let tpl = `My name is ${person.name}.`;
And
let MyVar = "My name is "+ person.name+".";
I am already able to get the string MyVar concatenated with person.name here, so what would be the scenario to use the template literal in?
If you are using template literals only with placeholders (e.g. `Hello ${person.name}`) like in the question's example, then the result is the same as just concatenating strings. Subjectively it looks better and is easier to read, especially for multi-line strings or strings containing both ' and " since you don't have to escape those characters any more.
Readability is a great feature, but the most interesting thing about templates are Tagged template literals:
let person = {name: 'John Smith'};
let tag = (strArr, name) => strArr[0] + name.toUpperCase() + strArr[1];
tag `My name is ${person.name}!` // Output: My name is JOHN SMITH!
In the third line of this example, a function named tag is called. The content of the template string is split into multiple variables, that you can access in the arguments of the tag function: literal sections (in this example the value of strArr[0] is My name is and the value of strArr[1] is !) and substitutions (John Smith). The template literal will be evaluated to whatever the tag function returns.
The ECMAScript wiki lists some possible use cases, like automatically escaping or encoding input, or localization. You could create a tag function named msg that looks up the literal parts like My name is and substitutes them with translations into the current locale's language, for example into German:
console.log(msg`My name is ${person.name}.`) // Output: Mein Name ist John Smith.
The value returned by the tag function doesn't even have to be a string. You could create a tag function named $ which evaluates the string and uses it as a query selector to return a collection of DOM nodes, like in this example:
$`a.${className}[href=~'//${domain}/']`
ES6 comes up with a new type of string literal, using the ` back-tick as the delimiter. These literals do allow basic string interpolation expressions to be embedded, which are then automatically parsed and evaluated.
let actor = {name: 'RajiniKanth', age: 68};
let oldWayStr = "<p>My name is " + actor.name + ",</p>\n" +
"<p>I am " + actor.age + " old</p>\n";
let newWayHtmlStr =
`<p>My name is ${actor.name},</p>
<p>I am ${actor.age} old</p>`;
console.log(oldWayStr);
console.log(newWayHtmlStr);
As you can see, we used the ..`` around a series of characters, which are interpreted as a string literal, but any expressions of the form ${..} are parsed and evaluated inline immediately.
One really nice benefit of interpolated string literals is they are allowed to split across multiple lines:
var Actor = {"name" : "RajiniKanth"};
var text =
`Now is the time for all good men like ${Actor.name}
to come to the aid of their
country!`;
console.log( text );
// Now is the time for all good men
// to come to the aid of their
// country!
Interpolated Expressions
Any valid expression is allowed to appear inside ${..} in an interpolated string lit‐ eral, including function calls, inline function expression calls, and even other interpo‐ lated string literals!
function upper(s) {
return s.toUpperCase();
}
var who = "reader"
var text =
`A very ${upper( "warm" )} welcome
to all of you ${upper( `${who}s` )}!`;
console.log( text );
// A very WARM welcome
// to all of you READERS!
Here, the inner ${who}s`` interpolated string literal was a little bit nicer convenience for us when combining the who variable with the "s" string, as opposed to who + "s". Also to keep an note is an interpolated string literal is just lexically scoped where it appears, not dynamically scoped in any way:
function foo(str) {
var name = "foo";
console.log( str );
}
function bar() {
var name = "bar";
foo( `Hello from ${name}!` );
}
var name = "global";
bar(); // "Hello from bar!"
Using the template literal for the HTML is definitely more readable by reducing the annoyance.
The plain old way:
'<div class="' + className + '">' +
'<p>' + content + '</p>' +
'Let\'s go'
'</div>';
With ES6:
`<div class="${className}">
<p>${content}</p>
Let's go
</div>`
Your string can span multiple lines.
You don't have to escape quotation characters.
You can avoid groupings like: '">'
You don't have to use the plus operator.
Tagged Template Literals
We can also tag a template string, when a template string is tagged, the literals and substitutions are passed to function which returns the resulting value.
function myTaggedLiteral(strings) {
console.log(strings);
}
myTaggedLiteral`test`; //["test"]
function myTaggedLiteral(strings,value,value2) {
console.log(strings,value, value2);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// "Neat"
// 5
We can use the spread operator here to pass multiple values. The first argument — we called it strings — is an array of all the plain strings (the stuff between any interpolated expressions).
we then gather up all subsequent arguments into an array called values using the ... gather/rest operator, though you could of course have left them as individual named parameters following the strings parameter like we did above (value1, value2 etc).
function myTaggedLiteral(strings,...values) {
console.log(strings);
console.log(values);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// ["Neat", 5]
The argument(s) gathered into our values array are the results of the already evaluated interpolation expressions found in the string literal. A tagged string literal is like a processing step after the interpolations are evaluated but before the final string value is compiled, allowing you more control over generating the string from the literal. Let's look at an example of creating a re-usable templates.
const Actor = {
name: "RajiniKanth",
store: "Landmark"
}
const ActorTemplate = templater`<article>
<h3>${'name'} is a Actor</h3>
<p>You can find his movies at ${'store'}.</p>
</article>`;
function templater(strings, ...keys) {
return function(data) {
let temp = strings.slice();
keys.forEach((key, i) => {
temp[i] = temp[i] + data[key];
});
return temp.join('');
}
};
const myTemplate = ActorTemplate(Actor);
console.log(myTemplate);
Raw Strings
Our tag functions receive a first argument we called strings, which is an array. But there’s an additional bit of data included: the raw unprocessed versions of all the strings. You can access those raw string values using the .raw property, like this:
function showraw(strings, ...values) {
console.log( strings );
console.log( strings.raw );
}
showraw`Hello\nWorld`;
As you can see, the raw version of the string preserves the escaped \n sequence, while the processed version of the string treats it like an unescaped real new-line. ES6 comes with a built-in function that can be used as a string literal tag: String.raw(..). It simply passes through the raw versions of the strings:
console.log( `Hello\nWorld` );
/* "Hello
World" */
console.log( String.raw`Hello\nWorld` );
// "Hello\nWorld"
It's a lot cleaner and as stated in the comments, is a common features in another languages.
The other thing that I found nice was the line breaks, very useful when writing strings.
let person = {name: 'John Smith', age: 24, greeting: 'Cool!' };
let usualHtmlStr = "<p>My name is " + person.name + ",</p>\n" +
"<p>I am " + person.age + " old</p>\n" +
"<strong>\"" + person.greeting +"\" is what I usually say</strong>";
let newHtmlStr =
`<p>My name is ${person.name},</p>
<p>I am ${person.age} old</p>
<p>"${person.greeting}" is what I usually say</strong>`;
console.log(usualHtmlStr);
console.log(newHtmlStr);
While my answer does not directly address the question, I thought it may be of some interest to point out one drawback of using template literals in favor of array join.
Let’s say I have
let patient1 = {firstName: "John", lastName: "Smith"};
let patient2 = {firstName: "Dwayne", lastName: "Johnson", middleName: "'The Rock'"};
So some patients have a middleName and others do not.
If I wanted a string representing the full name of a patient
let patientName = `${patient1.firstName} ${patient1.middleName} ${patient1.lastName}`;
Then this would become "John undefined Smith"
However if I did
let patientName = [patient1.firstName, patient1.middleName, patient1.lastName].join(" ");
Then this would become just "John Smith"
General_Twyckenham pointed out that a join on " " would result in an extra space between "John" and "Smith".
To get around this, you can have a filter before the join to get rid of falsy values:
[patient1.firstName, patient1.middleName, patient1.lastName].filter(el => el).join(" ");
I have the following code for ECMAScript 6 template literals:
let person = {name: 'John Smith'};
let tpl = `My name is ${person.name}.`;
let MyVar = "My name is " + person.name + ".";
console.log("template literal= " + tpl);
console.log("my variable = " + MyVar);
The output is as follows:
template literal= My name is John Smith.
my variable = My name is John Smith.
This is the fiddle.
I tried searching for the exact difference, but I couldn't find it,
What is the difference between the following two statements?
let tpl = `My name is ${person.name}.`;
And
let MyVar = "My name is "+ person.name+".";
I am already able to get the string MyVar concatenated with person.name here, so what would be the scenario to use the template literal in?
If you are using template literals only with placeholders (e.g. `Hello ${person.name}`) like in the question's example, then the result is the same as just concatenating strings. Subjectively it looks better and is easier to read, especially for multi-line strings or strings containing both ' and " since you don't have to escape those characters any more.
Readability is a great feature, but the most interesting thing about templates are Tagged template literals:
let person = {name: 'John Smith'};
let tag = (strArr, name) => strArr[0] + name.toUpperCase() + strArr[1];
tag `My name is ${person.name}!` // Output: My name is JOHN SMITH!
In the third line of this example, a function named tag is called. The content of the template string is split into multiple variables, that you can access in the arguments of the tag function: literal sections (in this example the value of strArr[0] is My name is and the value of strArr[1] is !) and substitutions (John Smith). The template literal will be evaluated to whatever the tag function returns.
The ECMAScript wiki lists some possible use cases, like automatically escaping or encoding input, or localization. You could create a tag function named msg that looks up the literal parts like My name is and substitutes them with translations into the current locale's language, for example into German:
console.log(msg`My name is ${person.name}.`) // Output: Mein Name ist John Smith.
The value returned by the tag function doesn't even have to be a string. You could create a tag function named $ which evaluates the string and uses it as a query selector to return a collection of DOM nodes, like in this example:
$`a.${className}[href=~'//${domain}/']`
ES6 comes up with a new type of string literal, using the ` back-tick as the delimiter. These literals do allow basic string interpolation expressions to be embedded, which are then automatically parsed and evaluated.
let actor = {name: 'RajiniKanth', age: 68};
let oldWayStr = "<p>My name is " + actor.name + ",</p>\n" +
"<p>I am " + actor.age + " old</p>\n";
let newWayHtmlStr =
`<p>My name is ${actor.name},</p>
<p>I am ${actor.age} old</p>`;
console.log(oldWayStr);
console.log(newWayHtmlStr);
As you can see, we used the ..`` around a series of characters, which are interpreted as a string literal, but any expressions of the form ${..} are parsed and evaluated inline immediately.
One really nice benefit of interpolated string literals is they are allowed to split across multiple lines:
var Actor = {"name" : "RajiniKanth"};
var text =
`Now is the time for all good men like ${Actor.name}
to come to the aid of their
country!`;
console.log( text );
// Now is the time for all good men
// to come to the aid of their
// country!
Interpolated Expressions
Any valid expression is allowed to appear inside ${..} in an interpolated string lit‐ eral, including function calls, inline function expression calls, and even other interpo‐ lated string literals!
function upper(s) {
return s.toUpperCase();
}
var who = "reader"
var text =
`A very ${upper( "warm" )} welcome
to all of you ${upper( `${who}s` )}!`;
console.log( text );
// A very WARM welcome
// to all of you READERS!
Here, the inner ${who}s`` interpolated string literal was a little bit nicer convenience for us when combining the who variable with the "s" string, as opposed to who + "s". Also to keep an note is an interpolated string literal is just lexically scoped where it appears, not dynamically scoped in any way:
function foo(str) {
var name = "foo";
console.log( str );
}
function bar() {
var name = "bar";
foo( `Hello from ${name}!` );
}
var name = "global";
bar(); // "Hello from bar!"
Using the template literal for the HTML is definitely more readable by reducing the annoyance.
The plain old way:
'<div class="' + className + '">' +
'<p>' + content + '</p>' +
'Let\'s go'
'</div>';
With ES6:
`<div class="${className}">
<p>${content}</p>
Let's go
</div>`
Your string can span multiple lines.
You don't have to escape quotation characters.
You can avoid groupings like: '">'
You don't have to use the plus operator.
Tagged Template Literals
We can also tag a template string, when a template string is tagged, the literals and substitutions are passed to function which returns the resulting value.
function myTaggedLiteral(strings) {
console.log(strings);
}
myTaggedLiteral`test`; //["test"]
function myTaggedLiteral(strings,value,value2) {
console.log(strings,value, value2);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// "Neat"
// 5
We can use the spread operator here to pass multiple values. The first argument — we called it strings — is an array of all the plain strings (the stuff between any interpolated expressions).
we then gather up all subsequent arguments into an array called values using the ... gather/rest operator, though you could of course have left them as individual named parameters following the strings parameter like we did above (value1, value2 etc).
function myTaggedLiteral(strings,...values) {
console.log(strings);
console.log(values);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// ["Neat", 5]
The argument(s) gathered into our values array are the results of the already evaluated interpolation expressions found in the string literal. A tagged string literal is like a processing step after the interpolations are evaluated but before the final string value is compiled, allowing you more control over generating the string from the literal. Let's look at an example of creating a re-usable templates.
const Actor = {
name: "RajiniKanth",
store: "Landmark"
}
const ActorTemplate = templater`<article>
<h3>${'name'} is a Actor</h3>
<p>You can find his movies at ${'store'}.</p>
</article>`;
function templater(strings, ...keys) {
return function(data) {
let temp = strings.slice();
keys.forEach((key, i) => {
temp[i] = temp[i] + data[key];
});
return temp.join('');
}
};
const myTemplate = ActorTemplate(Actor);
console.log(myTemplate);
Raw Strings
Our tag functions receive a first argument we called strings, which is an array. But there’s an additional bit of data included: the raw unprocessed versions of all the strings. You can access those raw string values using the .raw property, like this:
function showraw(strings, ...values) {
console.log( strings );
console.log( strings.raw );
}
showraw`Hello\nWorld`;
As you can see, the raw version of the string preserves the escaped \n sequence, while the processed version of the string treats it like an unescaped real new-line. ES6 comes with a built-in function that can be used as a string literal tag: String.raw(..). It simply passes through the raw versions of the strings:
console.log( `Hello\nWorld` );
/* "Hello
World" */
console.log( String.raw`Hello\nWorld` );
// "Hello\nWorld"
It's a lot cleaner and as stated in the comments, is a common features in another languages.
The other thing that I found nice was the line breaks, very useful when writing strings.
let person = {name: 'John Smith', age: 24, greeting: 'Cool!' };
let usualHtmlStr = "<p>My name is " + person.name + ",</p>\n" +
"<p>I am " + person.age + " old</p>\n" +
"<strong>\"" + person.greeting +"\" is what I usually say</strong>";
let newHtmlStr =
`<p>My name is ${person.name},</p>
<p>I am ${person.age} old</p>
<p>"${person.greeting}" is what I usually say</strong>`;
console.log(usualHtmlStr);
console.log(newHtmlStr);
While my answer does not directly address the question, I thought it may be of some interest to point out one drawback of using template literals in favor of array join.
Let’s say I have
let patient1 = {firstName: "John", lastName: "Smith"};
let patient2 = {firstName: "Dwayne", lastName: "Johnson", middleName: "'The Rock'"};
So some patients have a middleName and others do not.
If I wanted a string representing the full name of a patient
let patientName = `${patient1.firstName} ${patient1.middleName} ${patient1.lastName}`;
Then this would become "John undefined Smith"
However if I did
let patientName = [patient1.firstName, patient1.middleName, patient1.lastName].join(" ");
Then this would become just "John Smith"
General_Twyckenham pointed out that a join on " " would result in an extra space between "John" and "Smith".
To get around this, you can have a filter before the join to get rid of falsy values:
[patient1.firstName, patient1.middleName, patient1.lastName].filter(el => el).join(" ");
var object = {
mastermind : "Brain",
henchman: "Pinky",
battleCry: function (noOfBrains) {
return "They are " + this.henchman + " and the" +
Array(noOfBrains + 1).join(" " + this.mastermind);
}
};
var battleCry = object.battleCry(4);
--
Can you explain why array().join() return:
Correct: "They are Pinky and the Brain Brain Brain Brain"
Incorrect: "They are Pinky and the 5 Brain"
The array().join() is used to join all the elements of an array together in one string. Optionally, you can specify a delimiter to separate the elements.
In your code, Array(noOfBrains + 1) creates a new array with the given length, in your example 4 + 1 = 5 items, but all those 5 items are empty because your code doesn't assign anything to them. So your code is joining 5 empty strings using " Brain" as delimiter. Essentially, this function is actually a repeater of any string assigned to the mastermind property for as many times as you pass it.
Because in Array(noOfBrains + 1).join(" " + this.mastermind) this.mastermind contains the string "Brain". and noOfBrains is '4'. so it becomes Array(4+1).join(" " +"Brain") into Array(5).join(" Brain") will show the output as Brain Brain Brain Brain
This creates an array of a given length with undefined elements. In this example length of 5. When 5 elements are joined together there are 4 delimiters and each is delimiter is " Brain"
var dummyArray = Array(5);
console.log("Our Dummy Array");
console.log(dummyArray);
console.log();
console.log("Our Dummy Array Joined More Conventially");
console.log(dummyArray.join(","));
console.log();
console.log("Our Dummy Array Joined More Brainly");
console.log(dummyArray.join(" Brain"));
console.log();
Array join joins all elements of array to string using some string glue.
var a = ['one', 'two', 'three'];
console.log(a.join(', '));
You will see "one, two, three" in the console.
In your case glue is " Brain". Array is [5] - i mean array with one element which is 5 (4 + 1 = 5). So, [5].join(' Brain') = "5"
If you need repeat some string 2 or more times, you can use String.repeat(times).
In your case:
var bcObject = {
mastermind : "Brain",
henchman: "Pinky",
battleCry: function (noOfBrains) {
return "They are " + this.henchman + " and the" +
(' ' + this.mastermind).repeat(noOfBrains);
}
};
var battleCry = bcObject.battleCry(4);
I have the following code for ECMAScript 6 template literals:
let person = {name: 'John Smith'};
let tpl = `My name is ${person.name}.`;
let MyVar = "My name is " + person.name + ".";
console.log("template literal= " + tpl);
console.log("my variable = " + MyVar);
The output is as follows:
template literal= My name is John Smith.
my variable = My name is John Smith.
This is the fiddle.
I tried searching for the exact difference, but I couldn't find it,
What is the difference between the following two statements?
let tpl = `My name is ${person.name}.`;
And
let MyVar = "My name is "+ person.name+".";
I am already able to get the string MyVar concatenated with person.name here, so what would be the scenario to use the template literal in?
If you are using template literals only with placeholders (e.g. `Hello ${person.name}`) like in the question's example, then the result is the same as just concatenating strings. Subjectively it looks better and is easier to read, especially for multi-line strings or strings containing both ' and " since you don't have to escape those characters any more.
Readability is a great feature, but the most interesting thing about templates are Tagged template literals:
let person = {name: 'John Smith'};
let tag = (strArr, name) => strArr[0] + name.toUpperCase() + strArr[1];
tag `My name is ${person.name}!` // Output: My name is JOHN SMITH!
In the third line of this example, a function named tag is called. The content of the template string is split into multiple variables, that you can access in the arguments of the tag function: literal sections (in this example the value of strArr[0] is My name is and the value of strArr[1] is !) and substitutions (John Smith). The template literal will be evaluated to whatever the tag function returns.
The ECMAScript wiki lists some possible use cases, like automatically escaping or encoding input, or localization. You could create a tag function named msg that looks up the literal parts like My name is and substitutes them with translations into the current locale's language, for example into German:
console.log(msg`My name is ${person.name}.`) // Output: Mein Name ist John Smith.
The value returned by the tag function doesn't even have to be a string. You could create a tag function named $ which evaluates the string and uses it as a query selector to return a collection of DOM nodes, like in this example:
$`a.${className}[href=~'//${domain}/']`
ES6 comes up with a new type of string literal, using the ` back-tick as the delimiter. These literals do allow basic string interpolation expressions to be embedded, which are then automatically parsed and evaluated.
let actor = {name: 'RajiniKanth', age: 68};
let oldWayStr = "<p>My name is " + actor.name + ",</p>\n" +
"<p>I am " + actor.age + " old</p>\n";
let newWayHtmlStr =
`<p>My name is ${actor.name},</p>
<p>I am ${actor.age} old</p>`;
console.log(oldWayStr);
console.log(newWayHtmlStr);
As you can see, we used the ..`` around a series of characters, which are interpreted as a string literal, but any expressions of the form ${..} are parsed and evaluated inline immediately.
One really nice benefit of interpolated string literals is they are allowed to split across multiple lines:
var Actor = {"name" : "RajiniKanth"};
var text =
`Now is the time for all good men like ${Actor.name}
to come to the aid of their
country!`;
console.log( text );
// Now is the time for all good men
// to come to the aid of their
// country!
Interpolated Expressions
Any valid expression is allowed to appear inside ${..} in an interpolated string lit‐ eral, including function calls, inline function expression calls, and even other interpo‐ lated string literals!
function upper(s) {
return s.toUpperCase();
}
var who = "reader"
var text =
`A very ${upper( "warm" )} welcome
to all of you ${upper( `${who}s` )}!`;
console.log( text );
// A very WARM welcome
// to all of you READERS!
Here, the inner ${who}s`` interpolated string literal was a little bit nicer convenience for us when combining the who variable with the "s" string, as opposed to who + "s". Also to keep an note is an interpolated string literal is just lexically scoped where it appears, not dynamically scoped in any way:
function foo(str) {
var name = "foo";
console.log( str );
}
function bar() {
var name = "bar";
foo( `Hello from ${name}!` );
}
var name = "global";
bar(); // "Hello from bar!"
Using the template literal for the HTML is definitely more readable by reducing the annoyance.
The plain old way:
'<div class="' + className + '">' +
'<p>' + content + '</p>' +
'Let\'s go'
'</div>';
With ES6:
`<div class="${className}">
<p>${content}</p>
Let's go
</div>`
Your string can span multiple lines.
You don't have to escape quotation characters.
You can avoid groupings like: '">'
You don't have to use the plus operator.
Tagged Template Literals
We can also tag a template string, when a template string is tagged, the literals and substitutions are passed to function which returns the resulting value.
function myTaggedLiteral(strings) {
console.log(strings);
}
myTaggedLiteral`test`; //["test"]
function myTaggedLiteral(strings,value,value2) {
console.log(strings,value, value2);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// "Neat"
// 5
We can use the spread operator here to pass multiple values. The first argument — we called it strings — is an array of all the plain strings (the stuff between any interpolated expressions).
we then gather up all subsequent arguments into an array called values using the ... gather/rest operator, though you could of course have left them as individual named parameters following the strings parameter like we did above (value1, value2 etc).
function myTaggedLiteral(strings,...values) {
console.log(strings);
console.log(values);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// ["Neat", 5]
The argument(s) gathered into our values array are the results of the already evaluated interpolation expressions found in the string literal. A tagged string literal is like a processing step after the interpolations are evaluated but before the final string value is compiled, allowing you more control over generating the string from the literal. Let's look at an example of creating a re-usable templates.
const Actor = {
name: "RajiniKanth",
store: "Landmark"
}
const ActorTemplate = templater`<article>
<h3>${'name'} is a Actor</h3>
<p>You can find his movies at ${'store'}.</p>
</article>`;
function templater(strings, ...keys) {
return function(data) {
let temp = strings.slice();
keys.forEach((key, i) => {
temp[i] = temp[i] + data[key];
});
return temp.join('');
}
};
const myTemplate = ActorTemplate(Actor);
console.log(myTemplate);
Raw Strings
Our tag functions receive a first argument we called strings, which is an array. But there’s an additional bit of data included: the raw unprocessed versions of all the strings. You can access those raw string values using the .raw property, like this:
function showraw(strings, ...values) {
console.log( strings );
console.log( strings.raw );
}
showraw`Hello\nWorld`;
As you can see, the raw version of the string preserves the escaped \n sequence, while the processed version of the string treats it like an unescaped real new-line. ES6 comes with a built-in function that can be used as a string literal tag: String.raw(..). It simply passes through the raw versions of the strings:
console.log( `Hello\nWorld` );
/* "Hello
World" */
console.log( String.raw`Hello\nWorld` );
// "Hello\nWorld"
It's a lot cleaner and as stated in the comments, is a common features in another languages.
The other thing that I found nice was the line breaks, very useful when writing strings.
let person = {name: 'John Smith', age: 24, greeting: 'Cool!' };
let usualHtmlStr = "<p>My name is " + person.name + ",</p>\n" +
"<p>I am " + person.age + " old</p>\n" +
"<strong>\"" + person.greeting +"\" is what I usually say</strong>";
let newHtmlStr =
`<p>My name is ${person.name},</p>
<p>I am ${person.age} old</p>
<p>"${person.greeting}" is what I usually say</strong>`;
console.log(usualHtmlStr);
console.log(newHtmlStr);
While my answer does not directly address the question, I thought it may be of some interest to point out one drawback of using template literals in favor of array join.
Let’s say I have
let patient1 = {firstName: "John", lastName: "Smith"};
let patient2 = {firstName: "Dwayne", lastName: "Johnson", middleName: "'The Rock'"};
So some patients have a middleName and others do not.
If I wanted a string representing the full name of a patient
let patientName = `${patient1.firstName} ${patient1.middleName} ${patient1.lastName}`;
Then this would become "John undefined Smith"
However if I did
let patientName = [patient1.firstName, patient1.middleName, patient1.lastName].join(" ");
Then this would become just "John Smith"
General_Twyckenham pointed out that a join on " " would result in an extra space between "John" and "Smith".
To get around this, you can have a filter before the join to get rid of falsy values:
[patient1.firstName, patient1.middleName, patient1.lastName].filter(el => el).join(" ");