ES6: Template Literals

Template literals is the new feature introduce in ES6. Previously string manipulation was very restricted. Was not able to parse variables in sting, had to concatenate. Same for multi line string.

In ES6 template string introduce by using back-ticks(` `) instead of single or double quotes for strings. A template string could  be written as :

Synatax

`Hello World!!`
var msg = `Hello Word!!`

 

Multiline String

For multiline string we need to use ‘\n’ for line break but in template literals string in next line will automatically treated as new line.

Syntax for multiline string

console.log("Hi Jon Doe.\n"+
"How are you?");
//"Hi Jon Doe.
//How are you?"

 

Syntax for same multiline string using template literals

console.log(`Hi Jon Doe.
How are you?`);
//"Hi Jon Doe.
//How are you?"

 

String Substitution

One of the best feature of templating, allows any valid javascript expression in template.

Syntax we use

var person = {name:'Jon Doe', age:42, sex:'Male'};
console.log(person.name +' is a '+person.age+' years old '+person.sex);
"Jon Doe is a 42 years old Male"

Syntax use string substitution

var person = {name:'Jon Doe', age:42, sex:'Male'};
console.log(`${person.name } is a ${person.age} years old ${person.sex}`);
"Jon Doe is a 42 years old Male"

Few more examples

var a = 10;
var b = 10;

console.log(`${a} + ${b} = ${a + b}`); // 10 + 10 = 20
console.log(`${a} * ${b} = ${a * b}`); // 10 * 10 = 100
console.log(`${a} ^ ${b} = ${Math.pow(a , b)}`); // 10 ^ 10 = 10000000000

 

var person = {name:'Jon Doe', age:42, sex:'Male'};

function salutation(sex){
  return (sex == 'Male') ? 'Mr.' : 'Miss.';
}

console.log(`Hello ${salutation(person.sex)} ${person.name}`);
//Hello Mr. Jon Doe

console.log(`Hello ${salutation(person.sex)} ${person.name.toUpperCase()}`);
//Hello Mr. JON DOE

 

Tagged template literals

Tagged template literals helps us to modify the output of a template literals using a function. The first argument contains an array of string literals . The second, and each argument after the first one, are the values of the processed substitution expressions . In the end,  function returns processed string.

How we write it

getUrl([ "http://example.com/product?category=", "&id="],category, id);

How it be

getUrl`http://example.com/product?category=${category}&id=${id}`;

 

Lets see it in details

var category = 'demo', id = 201;
function getUrl(strings, val1, val2){
    return strings[0]+val1+strings[1]+val2;
}
getUrl([ "http://example.com/product?category=", "&id="],category, id);
"http://example.com/product?category=demo&id=201"

ES6 approach

var category = 'demo', id = 201;
function getUrl(strings, ...values){
    return strings[0]+values[0]+strings[1]+values[1];
}
getUrl`http://example.com/product?category=${category}&id=${id}`;
"http://example.com/product?category=demo&id=201"

ES6: Constant and block scoped variables

Constant

In javascript we can’t declare a variable as constant. But we can achieve it by using Object.defineProperty()

This method accepts three arguments: the object on which the property should be added or modified, the name of the property, and a descriptor object. The properties on the descriptor object match the attribute names: configurable, enumerable, writable, and value.

[[Configurable]] — Indicates if the property may be redefined by removing the property via delete, changing the property’s attributes, or changing the property into an accessor property.

[[Enumerable]] — true if and only if this property shows up during enumeration of the properties on the corresponding object.

[[Writable]] — Indicates if the property’s value can be changed. By default, this is true for all properties defined directly on an object.

[[Value]] — Contains the actual data value for the property. This is the location from which the property’s value is read and the location to which new values are saved. The default value for this attribute is undefined.

So to create a constant,  declare a global variable which will be part of global or window object  which value can’t be changed or alter or deleted.

Object.defineProperty(typeof global === "object" ? global : window, "PI", {
    value: 3.141593,
    enumerable: true,
    writable: false,
    configurable: false
});
PI => 3.141593

 

ES6 introduce const to declare constant which can’t be altered, deleted or re-declared.

const PI = 3.141593

PI => 3.141593

 

const VERSION = 2.0;

// this will throw an error
VERSION = 2.3;

// will print 2.0
console.log(VERSION);

// trying to redeclare a constant throws an error
const VERSION = 2.7;

// the name VERSION is reserved for constant above, so this will also fail
var VERSION = 3.0;

 

Block scoped variable

ES6 introduce a new keyword let to declare block scoped variable.  Let’s see the difference between var and let

function varTest() {
    var x = 1;
    if (true) {
        var x = 2;  // same variable!
        console.log(x);  // 2
    }
    console.log(x);  // 2
}

 

function letTest() {
    let x = 1;
    if (true) {
        let x = 2;  // different variable
        console.log(x);  // 2
    }
    console.log(x);  // 1
}

 

More Examples

var callbacks = [];
for (var i = 0; i <= 2; i++) {
    callbacks[i] = function() { return i * 2; };
}

callbacks[0]() => 6
callbacks[1]() => 6
callbacks[2]() => 6

 

This one is the classic example of closures. When all functions get called that time i reached to maximum value 3. To avoid this we use anonymous function.

var callbacks = [];
for (var i = 0; i <= 2; i++) {
    (function (i) {
        callbacks[i] = function() { return i * 2; };
    })(i);
}

callbacks[0]() => 0
callbacks[1]() => 2
callbacks[2]() => 4

 

In above example we handle closure and passed i as a parameter to the anonymous function and i became local inside that function.

In ES6 we can do it without handling closure by declaring in blocked scope

var callbacks = [];
for (let i = 0; i <= 2; i++) {
    callbacks[i] = function() { return i * 2; };
}

callbacks[0]() => 0
callbacks[1]() => 2
callbacks[2]() => 4

 

ES6: Parameter Handling

Parameter handling in ES6 gets improved a lot and makes developers life easy. We will see how it got better against ES5

Default parameter values

In ES5 it was quite complicated to set a default value to a function parameter if no value passed for that. Normally we checked that parameter defined or not and if undefined then we set it to default value like

function myFunc(name, age, sex){
    if(name === undefined)
        name = 'Jon Doe';
    if(age === undefined)
        age = 18;
    if(sex === undefined)
        sex = 'Male';
   return name+' is a '+age+' years old '+sex;
}

myFunc() => "Jon Doe is a 18 years old Male"
myFunc('Junior Doe', 5) => "Junior Doe is a 5 years old Male"
myFunc('Jane Doe', 49, 'Female') => "Jane Doe is a 49 years old Female"

Or like

function myFunc(name, age, sex){
    var name = name || 'Jon Doe';
    var age = age || 18;
    var sex = sex || 'Male';
   return name+' is a '+age+' years old '+sex;
}

myFunc() => "Jon Doe is a 18 years old Male"
myFunc('Junior Doe', 5) => "Junior Doe is a 5 years old Male"
myFunc('Jane Doe', 49, 'Female') => "Jane Doe is a 49 years old Female"

In ES6 we don’t need to check the parameter and then set it default value. We can do it directly in function definition like

function myFunc(name = 'Jon Doe', age = '18', sex = 'Male'){
   return name+' is a '+age+' years old '+sex;
}

myFunc() => "Jon Doe is a 18 years old Male"
myFunc('Junior Doe', 5) => "Junior Doe is a 5 years old Male"
myFunc('Jane Doe', 49, 'Female') => "Jane Doe is a 49 years old Female"

 

Passing undefined

In function if all parameters values are set to default but if we want to use few arguments default value.

Like

function myFunc(name = 'Jon Doe', age = '18', sex = 'Male')

 

We want to call this function with name and sex and want age to be default value then we need to pass undefined (not null). undefined  always replace with default value if any.

 

myFunc('Jane Doe', undefined, 'Female') => "Jane Doe is a 18 years old Female"

 

Call time evaluation

All default arguments get evaluated while function called and new object gets created for each call like.

function fruits(name, all = []){
    all.push(name);
    return all;
}

fruits('apple') => ['apple']
fruits('mango') => ['mango'] not ['apple', 'mango']

 

Defaults are available to next defaults

Parameters already fetched are available to next default parameters

function fruits(fruits, fewFruits = 'Few '+fruits, manyFruits = 'Many '+fruits){
    return [fruits, fewFruits, manyFruits];
}

fruits('Mangoes') => ['Mangoes', 'Few Mangoes', 'Many Mangoes']

 

Rest Parameters

Each function has its own arguments array. arguments array created automatically inside each function and contains all parameters passed to function.

function myFunc(name, age)
myFunc('Jon Doe', 24)

Here myFunc arguments will contain name and age both. We can loop through arguments and get all values.

function myFunc(name, age)
myFunc('Jon Doe', 24, 'Female', 'Hispanic', 'French')

In above call we passed  3 extra parameter for sex, ethnicity and language. Though myFunc function doesn’t has any named parameter for those extra parameters, we can’t access those values directly. We can get those from arguments.

Here arguments  contains all named as well as unnamed parameters. If we want to retrieve all unnamed parameters then there are no direct way to get in ES5. Only way to get it by slicing arguments

function myFunc(name, age){
   var extras = Array.prototype.slice.call(arguments, myFunc.length);
   //or
   // var extras = Array.prototype.slice.call(arguments, 2);
   return extras;
}
myFunc('Jon Doe', 24, 'Female', 'Hispanic', 'French') => ['Female', 'Hispanic', 'French']

NOTE: functionName.length returns the number of parameters that function expects.

In ES6 a new property introduced called rest parameters which holds all unnamed parameters only like

function myFunc(name, age, ...extras){
   return extras;
}
myFunc('Jon Doe', 24, 'Female', 'Hispanic', 'French') => ['Female', 'Hispanic', 'French']

 

Example

Here we are taking an example, calculation power of numbers where first parameter is the power and second the rest parameter which contains an array of elements.

function power(power, ...theArgs) {
   return theArgs.map(function (element) {
      return Math.pow(element, power);
   });
}
power(2,1,2,3,4,5) => [1,4,9,16,25]
power(3,1,2,3,4,5) => [1,8,27,64,125]

 

Better Examples

If a functions expects few parameters then while we call that function, we can’t pass all parameters in an array, need to pass individually like

function myFunc(name, age, sex)
var args = ['Jon Doe', 24, 'Male'];
myFunc(args) //doesn't work
function myFunc(name, age, sex)
var args = ['Jon Doe', 24, 'Male'];
myFunc(args[0], args[1], args[2]) // works
myFunc.apply(null,args) // works

In ES6 it’s like

function myFunc(name, age, sex)
var args = ['Jon Doe', 24, 'Male'];
myFunc(...args) //works

 

function myFunc(name, age, sex, ethnicity, language)
var args = [ 24, 'Male', 'Hispanic'];
myFunc('Jon Doe', ...args, 'French') //works