f-strings in Python

Python f-strings or formatted strings are new way of formatting strings introduced in Python 3.6 under PEP-498. It’s also called literal string interpolation. They provide a better way to format strings and make debugging easier too.

What are f-strings?

Strings in Python are usually enclosed in “ ” (double quotes) or ‘ ‘ ( single quotes). To create f-Strings, you only need to add an f or an F before the opening quotes of your string. For example,

“Anna” is a string whereas f”Anna” is an f-String.

f-Strings provide a concise and convenient way to embed python expressions inside string literals for formatting.

Why do we need f-Strings?

Before Python 2.6, to format a string, one would either use % operator or string.Template module. Later str.format method came along and added to the language a more flexible and robust way of formatting a string.

%formatting: great for simple formatting but limited support for strings, ints, doubles etc., We can’t use it with objects.

msg = ‘hello world’

‘msg: %s’ % msg

Output:
'msg: hello world'
Template strings:

Template strings are useful for keyword arguments like dictionaries. We cannot call any function and arguments must be string.

msg = ‘hello world’

‘msg: {}’.format(msg)

Output:
'msg: hello world'
String format():

String format() function was introduced to overcome the limitations of %formatting and template strings. But this also has verbosity.

age = 3 * 10

‘My age is {age}.’.format(age=age)

Output:
'My age is 30.'

Introduction of f-string in Python is to have minimal syntax for string formatting.

f-String Syntax:
f"This is an f-string {var_name} and {var_name}."

Enclosing of variables are within  curly braces {}

Example:

val1 = ‘Abaython’

val2 = ‘Python’

print(f”{val1} is a portal for {val2}.”)

Output:
Abaython is a portal for Python.

How to evaluate expressions in f-String?

We can evaluate valid expressions on the fly using,

num1 = 25

num2 = 45

print(f”The product of {num1} and {num2} is {num1 * num2}.”)

Output:
The product of 25 and 45 is 1125.
How to call functions using f-String?

def mul(x, y):

    return x * y

print(f’Product(10,20) = {mul(10, 20)}’)

Output:
Product(10,20) = 200

What are getter and setter methods in JavaScript?

Before jumping into getter and setter. There are two kinds of object properties in JavaScript: data properties and accessor property

Data property:

Example of data property,

const employee = {
  //data property
  firstname: 'Anna';
};
Accessor property:

Accessor properties are functions that execute on getting and setting a value of an object. Accessors are useful when some operations are needed to be performed automatically before setting or retrieving an object’s value, like reformating strings, accessing private properties, triggering events, etc.

  • get – to define a getter method to get the property value.
  • set – to define a setter method to set the property value.

JavaScript getter and setter methods are useful in accessing the object properties. It is used for Data Encapsulation. You can ensure higher quality data while using getter and setter methods. Getters areuseful in reading the values of properties and setters are useful in writing the value to properties.

Getters method:

Getter methods are used to access the properties of an object.

Syntax:
let obj = {
  get propName() {
    // getter, the code executed on getting obj.propName
  },
Example:
const employee = {

    // data property
    firstName: 'Anna',
    
    // accessor property(getter)
    get getName() {
        return this.firstName;
    }
};
// accessing data property
console.log(employee.firstName); // Anna

// accessing getter methods
console.log(employee.getName); // Anna

// trying to access as a method
console.log(employee.getName()); // error
Output:

Anna

Anna

Type error

Here getter method getName() is created to access the property of an object and when we try to access value as a method like employee.getName() an error occurs.

Setter Methods:

Setter methods are useful in changing or writing the value of a property in an object. It is always a great way to ensure the value of a property in an object is correct. It takes one argument which is the value you want to set.

Syntax:
set propName(value) {
    // setter, the code executed on setting obj.propName = value
  }
};
Example,
const employee = {
    firstName: 'Anna',
    
    //accessor property(setter)
    set changeName(newName) {
        this.firstName = newName;
    }
};
console.log(employee.firstName); // Anna

// change(set) object property using a setter
employee.changeName = 'Tim';

console.log(employee.firstName); // Tim
Output:

Anna

Tim

Setter method must have one formal parameter.

Object.defineProperty():

We can also use Object.defineProperty() method to add getters and setters.

Syntax:
Object.defineProperty(obj,prop,descriptor)

obj – object name

prop – property name

descriptor – describes the property

const employee = {
    firstName: 'Anna'
}
// getting property
Object.defineProperty(employee, "getName", {
    get : function () {
        return this.firstName;
    }
});
// setting property
Object.defineProperty(employee, "changeName", {
    set : function (value) {
        this.firstName = value;
    }
});

console.log(employee.firstName); // Anna
// changing the property value
employee.changeName = 'Tim';

console.log(employee.firstName); // Tim
Output:

Anna

Tim

The above example shows how object.defineProperty() is useful in setting getter and setter methods.

Why getters and setters?
  • Allows to control accessing and modification of object properties.
  • Validate data before setting it to an object.
  • Creates property that calculates on the fly.

How to destructure arrays and objects in JavaScript?

Before getting into destructuring, lets have a quick recap on arrays and objects.

  • Objects allows us to create a single entity that gather data items by key.

const emp = {

  name: “Anna”,

  id: “101”,

};

  • Array allows us to gather data items into an ordered list.

const emp = [“Anna”,”Tina”,”Tim”];

Destructuring introduced in ES6 allows us to unpack elements in an array or elements. It extracts multiple properties, items and values from an array or object into a separate variable.

Object Destructuring:

Syntax:
let { var1,var2} ={var1:val1, var2:val2}

To destruct object we use curly braces { }

Consider you have a student object with properties firstname and lastname.

let student = {

    firstname: "Anna",

    lastname: "Hills"

};
Prior to ES6:

For assigning properties and values to variables we have,

let student = {

    firstname: “Anna”,

    lastname: “Hills”

};

let firstName = student.firstname;

let lastName = student.lastname;

console.log(firstName);

console.log(lastName);

From ES6:
// assigning object attributes to variables
let student = {
    firstname: "Anna",
    lastname: "Hills"
};
// destructuring assignment
let { firstname, lastname} = student;
console.log(firstname); // Anna
console.log(lastname); // Hills
In the above example we have used the same variable names.
How to assign new variable name?
// assigning object attributes to variables
let student = {
    firstname: "Anna",
    lastname: "Hills"
};
// destructuring assignment to new variable
let { firstname:fname, lastname:lname} = student;
console.log(fname); // Anna
console.log(lname); // Hills

The order of the name in the object is not important we can also write as,

let {lastname, firstname} = student;
How to assign default values?

We can pass default values as follows,

let student = {
    firstname: "Anna",
    lastname: "Hills"
};
let { firstname, lastname, age = 22} = student;
console.log(age); //22
Output:

22

How to assign multiple object properties to single variable?
const student = {
    firstname: 'Anna',
    lastname: 'Hills',
    age: 25,
    gender: 'female'    
}
// destructuring assignment
// assigning remaining properties to rest
let { firstname, ...details } = student;

console.log(firstname); // Anna
console.log(details); // {lastname: 'Hills', age: 25, gender: 'female'}
Output:

Anna

{ lastname: ‘Hills’, age: 25, gender: ‘female’ }

Nested destructuring in objects:

In order to execute the nested destructuring assignment for objects, you have to enclose the variables in an object structure (by enclosing inside {}).

const student = {
    name: 'Anna',
    age: 26,
    details: {
        course: 'Javascript',
        fee: 2500
    }
}
// nested destructuring 
const {name, details: {course, fee}} = student;
console.log(name); // Anna
console.log(course); // Javascript
console.log(fee); // 2500
Output:

Anna

Javascript

2500

Array destructuring:

To destruct arrays we use square brackets [ ].

Syntax:
const [var1,var2,…] = arrayName;
Example:
const arrValue = ['Anna', 'Tina', 'Lena'];

// destructuring assignment in arrays
const [x, y, z] = arrValue;

console.log(x); 
console.log(y); 
console.log(z); 
Output:

Anna

Tina

Lena

How to assign default values?
let arr1 = [20];
// assigning default value 5 and 7
let [x = 10,  y = 9] = arr1;
console.log(x); // 20
console.log(y); // 9

In the above array we have one element so when we assign default values only y=9 is assigned and x=20 remains the same.

Output:

20

9

How to swap variables using destructuring assignment?
// program to swap variables
let x = 10;
let y = 20;
// swapping variables
[x, y] = [y, x];
console.log(x); // 20
console.log(y); // 10
Output:

20

10

How to skip assigning unwanted items in an array?

We can skip assigning unwanted items in an array to a local variable using comma ( , )

const arr1 = ['one', 'two', 'three'];
// destructuring assignment in arrays
const [x, , z] = arr1;
console.log(x); // one
console.log(z); // three
Output:

one

three

How to assign multiple elements to a single variable?

We can assign multiple elements to a single variable using spread syntax …

const arr1 = ['one', 'two', 'three', 'four'];
// destructuring assignment in arrays
// assigning remaining elements to y
const [x, ...y] = arr1;
console.log(x); // one
console.log(y); // ["two", "three", "four"]
Output:

one

[ ‘two’, ‘three’, ‘four’ ]

one is assigned to x variable. Rest of the elements are assigned to y variable.

Nested Destructuring Assignment in arrays:

In order to execute the nested destructuring assignment, you have to enclose the variables in an array structure (by enclosing inside []).

Nested destructuring in arrays is

// nested array elements
const arr1 = ['one', ['two', 'three', 'four']];
// nested destructuring assignment in arrays
const [a, [b, c, d]] = arr1;
console.log(a); // one
console.log(b); // two
console.log(c); // three
console.log(d); // four
Output:

one

two

three

four

Destructuring allows for instantly mapping an object or array to many variables.

How to clone object in JavaScript?

An object is an entity which has properties and types. It is a complicated datatype where it can store various data type.

const employee = {
  name:'Anna',
  id:101,
  age:35,
  salary:2000
};

In JavaScript, objects are reference values. To clone objects we cannot use assignment operator (=). Using assignment operator (=)  we are creating only an alias for existing object.

What is Shallow copy?

Shallow copy or clone copies only the actual object. Nested objects are not copied. Since mutable and stored as reference, when assigning object to another variable, we are assigning objects memory address to variable. It is a one-level deep copy.

Using Spread operator:
const employee = {
  name:'Anna',
  id:101,
  age:35,
  salary:2000
};
const empclone = {
  ...employee  // clone object using spread 
};
//changing value in employee
employee.salary=3000;
console.log(empclone);
console.log(employee);
Output:

{name:’Anna’, id:101, age:35, salary:2000}

{name: ‘Anna’, id: 101, age: 35, salary: 3000 }

Here we have created a shallow copy of object.Any change in original object is not reflected in copied object. But if object consists of nested child objects, any change in child object reflects in copied object.

Example:

const data = { name: “Anna”, age: 26, hobbies: [“Jogging”, “Tennis”, “Gym”] }

const dataCopy = { …data }

data.hobbies[0] = “Swimming”

console.log(data.hobbies)

console.log(dataCopy.hobbies)

Output:

[ ‘Swimming’, ‘Tennis’, ‘Gym’ ]

[ ‘Swimming’, ‘Tennis’, ‘Gym’ ]

Here hobbies is nested object and changing its value gets reflected in copy object.

Using Object.assign():

It is an alternative to spread operator. We can copy values and properties from one or more source object to a new object.

Syntax:
const clone = Object.assign({}, object);
Example:
const employee = {
  name:'Anna',
  id:101,
  age:35,
  salary:2000
};
const empclone = Object.assign({}, employee); // copy using Object.assign()
console.log(empclone);
Output:

{name: ‘Anna’, id: 101, age: 35, salary: 2000 }

Here the second argument employee is copied to first argument {} of assign method.

This is also shallow copy like spread operator.

Deep Copy:

In JavaScript deep copy allows us to create a completely independent copy of original object. It has the same properties but does not share the same references as original object. Any change to one object will not reflect in another object. Deep copy is performed using the methods JSON.parse() and JSON.stringify().

Using JSON.parse():
Syntax:
const clone= JSON.parse(JSON.stringify(Objname))
Example:
const employee = {
  name:'Anna',
  id:101,
  age:35,
  salary:2000
};
const empclone = JSON.parse(JSON.stringify(employee));
console.log(empclone);
Output:

{ name: ‘Anna’, id: 101, age: 35, salary: 2000 }

Example:
// Deep Clone
obj = {
  a: 1,
  b: {
    c: 1
  }
};
let cloneObj = JSON.parse(JSON.stringify(obj));
obj.a = 2;
obj.b.c = 2;
console.log(JSON.stringify(obj)); // { a: 2, b: { c: 2}}
console.log(JSON.stringify(cloneObj)); // { a: 0, b: { c: 0}}
cloneObj.a = 4;
cloneObj.b.c = 4;
console.log(JSON.stringify(obj)); // { a: 2, b: { c: 2}}
console.log(JSON.stringify(cloneObj)); // { a: 4, b: { c: 4}}
Output:

{“a”:2,”b”:{“c”:2}}

{“a”:1,”b”:{“c”:1}}

{“a”:2,”b”:{“c”:2}}

{“a”:4,”b”:{“c”:4}}

As you can see from above example that copied object is independent but it can contain incorrect values in some cases. Another drawback is it works well only with primitive datatypes like numbers, strings and Boolean.

To overcome this we have structuredClone() function.

Using structuredClone():

It creates a deep clone of an object. It overcomes many short comings of JSON.parse().

Clone inifitely nested objects and arrays.

Copy circular references.

Clone a many data types like map, set, date, RegEx, etc.,

Transfer any transferable object.

Syntax:
structuredClone(value)
structuredClone(value, options)

value – Object to clone.

Options (optional)- object with properties as follows:

transfer- An array of transferable objects that will be moved rather than cloned to the returned object.

Return value- returns a deep copy of an object.

Supported platforms:
  • Chrome 98
  • Safari 137
  • Firefox 94
  • Node.js 17.0
  • Deno 1.14

On platforms that don’t support we can use polyfills.

Example:
const employee = {
  name:'Anna',
  id:101,
  age:35,
  salary:2000
};
const empclone = structuredClone(employee);
console.log(empclone);
Output:

{name: ‘Anna’, id: 101, age: 35, salary: 2000}

Points to note:
To perform shallow copy:
  • The spread operator
  • The Object.assign() method.
To perform deep copy:
  • The JSON parsing approach
  • The structuredClone() method.

Higher order function in JavaScript

A function is a reusable piece of code introduced to avoid repetitive code and improve code readability and quality. In Javascript, functions are first-class citizens. Here we can take a function as an argument or return a function. This ability to accept and return a function makes it first class citizens in JavaScript. Higher order functions are functions that take a function as parameter and return a funcction as output.

Function as first-class citizens:

Some operations performed on functions in javascript which make it feel like first-class citizens are

  • Store function in a variable.
  • Store function in array.
  • Accept another function as argument or as a return from a function.
  • Set a function as object property.
Higher order functions:

A function which accepts another function as an argument or as a return from a function is higher order function.

Function that takes another function as argument:

A function which can be passed as an argument to another function is called callback functions. In javascript functions are objects, so they can be passed as an argument.

function getname(myname) {
  // Invoke the passed function
  myname();
}

// Invoke the function by passing a function as an argument
getname(function(){
  console.log('Abaython');
});

Output:Abaython
Return function:

Here a function is returned from a function.

// Define a function that returns a function
function returnFunc() {
  return function() {
    console.log('Abaython');
  }
}

// Take the returned function in a variable.
const fn = returnFunc();
// Now invoke the returned function.
fn(); // Abaython
// Alternatively 
returnFunc()(); // Abaython
Output:

Abaython

Abaython

In JavaScript we have forEach(), map(), reduce() and filter() functions which are built-in higher order functions.

.forEach():

Iterate through an array of elements. It is used only with arrays. It takes a callback function with elements, index and array.

let sum = 0;
const numbers = [10, 20, 30, 40, 50];
numbers.forEach(num => sum+=num)
console.log(sum);
Output: 150
map():

Iterate an array and modify the elements of array. It takes a callback function with elements, index, array parameter and return a new array.

const num = [10, 20, 30, 40, 50]
const double = num.map((num) => num + num)
console.log(double)
Output: [ 20, 40, 60, 80, 100 ]
filter():

filter a set of elements which satisfies a certain condition and return a new array.

const num = [10, 20, 30, 40, 50]
const num1 = num.filter((num) => num>30)
console.log(num1)
Output: [ 40, 50 ]
reduce():

The reduce method executes the callback function on each member of the calling array which results in a single output value. The reduce method accepts two parameters: The reducer function (callback) and an optional initialValue.

The callback function  in turn accepts the following four parameters:

  • Accumulator
  • Current value
  • Current index
  • Source array
const num = [10, 20, 30, 40, 50]
const sum = num.reduce((acc, cur) => acc + cur, 0)
console.log(sum)
Output: 150

In a nutshell, higher order function are helpful in making a cleaner, readable and quality code.

Understanding rest and spread operator

ES6 has some great features that makes working with parameters and arrays easy. JavaScript uses three dots ( … ) for both the rest and spread operators. The main difference between these two operators is that rest operator collects a set of elements and stores them into a single array and spread operator expands an array of elements into a list of individual elements.

Spread operator:

Spread operator expands the values in an iterable like array or strings across zero or more arguments or elements. It is used to split up array of elements and object properties. Using spread operator we can combine two arrays more easily.

const arr1 = ['a','b','c'];
const arr2 = ['d','e','f'];
const combine = [ ...arr1, ...arr2];//spread operator
console.log(combine);
Output:

[ ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’ ]

When using spread, we are expanding a single variable into more.

Spread in function call:
function sum(n1,n2)
{
    console.log(n1+n2);
}
let arr=[10,20];
sum(...arr);//spread in function call
Output:

30

As you can see spread operator takes parameters and spreads them across arguments in function call.

What will happen if we have to work with unknown number of parameters?

Answer is using rest operator.

Rest operator:

It’s a collection of remaining elements. Useful for merging functional arguments into an array. We can use when we don’t know how many functional arguments are passed to our method.

const find_greater= (...args) => {

  console.log(args); /* lets see what's in args */

  return console.log(args.filter((x) => x > 25))

}

find_greater(25,36,42,12,17,9,58);
Output:

[25,36,42,12,17,9,58]

[36,42,58]

Another example,
function sum(first, ...others){

  for(let i=0; i<others.length; i++)

    first+=others[i];

  return first;

}

console.log(sum(12,14,22,15,9,7));

let [c,...rest] = [12,14,22,15,9,7];

console.log(...rest);

console.log(c);
Output:

79

14 22 15 9 7

12

Rest parameter have to be at the last because it collects all the remaining parameters into an array.

Rest is a collector. It collects the remaining elements.

Rest vs Spread Operator:
RestSpread
Rest operator allows us to pass an indefinite number of arguments to function by accumulating these several values into an array. Spread operator spreads or expands the values in an array or a string across one or more arguments.
The spread operator in JavaScript expands values in arrays and strings into individual elementsThe rest operator puts the values of user-specified data into a JavaScript array

Arrow function in JavaScript

Arrow functions expression is an alternative to traditional function expression. They are similar to lambda functions in python. These functions are often used in passing a function as a parameter to higher order functions. It is one of the features introduced in ES6.

The function ,

// function expression
let x = function(x, y) {
   return x * y;
}

Can be written as

// using arrow functions
let x = (x, y) => x * y;
Syntax:
let myFunction = (arg1, arg2, ...argN) => {
    statement(s)
}

myFunction – name of function

arg1,arg2,…argN – arguments of function

statement(s) – function body

Example:

The below example illustrates arrow functions with

  • No arguments
  • Single argument
  • Function expression
  • Function body
No arguments:
// with no argument
let noarg = () => console.log('Abaython');
noarg(); // Abaython
One argument:
// with one argument

let onearg = x => console.log(x);

onearg('Abaython'); // Abaython
As Expression:
//as expression
let num = 50;
let func = (num > 20) ?
  () => console.log('Greater than 20') :
  () => console.log('Less than 20');
func(); // Greater than 20
Function Body:
let sum = (a, b) => {

    let result = a + b;

    return result;

}

let result1 = sum(10,20);

console.log(result1); // 30
Output:

Abaython

Abaython

Greater than 20

30

Arrow functions and this keyword:

In a regular function this keyword refers to the function where it is called. But arrow functions does not have this and it refers to its parents scope whenever called.

function Employee() {
    this.name = 'Anna',
    this.age = 25,
    this.sayName = function () {

        console.log(this.name);
        let Func = () => {
            console.log(this.name);
        }

        Func();
    }
}
const x = new Employee();
x.sayName();
Output:

Anna

Anna

Func() is defined within arrow. Inside the arrow this keyword refers to parents scope and returns this.name as Anna.

Argument bindings:

Arrow functions don’t have argument bindings.

let x = () => {
    console.log(arguments);
}
x(10, 20); // error
Output:

Reference error

To solve this use spread syntax.

let x = (...n) => {
    console.log(n);
}
x(10, 20); // [10, 20]
Output:

[10, 20]

Limitations:
  • Arrow functions does not have bindings to this, arguments or super and should be used as methods.
  • Calling arrow functions with new throws type error. They cannot be used as constructor.
  • They cannot use yield within their body and cannot be created as generator function.
  •  You should not use arrow functions to create methods inside objects.
Key differences with Regular function:
  • No prototype object for arrow functions
  • Duplicate-named parameters are not allowed.
  • Does not have argument object.
When to use them?

Arrow functions can be used when we need to bind this to the context and not to the function itself. It is a clear and concise way to write callbacks without exposing the scope that should be hidden.

In the coming article will try to ellaborate the difference with regular functions.

How to use closure inside loop?

In our previous article we have seen introduction about closure . Creating closure inside loops is bit more complicated as it creates undesirable outcomes.

Example:
var funcs = [];
for (var i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("i value is " + i);
  };
}

for (var k = 0; k < 3; k++) {
  funcs[k]();
}
Expected Output:

i value is 0

i value is 1

i value is 2

Actual Output:

i value is 3

i value is 3

i value is 3

This problem arises when we use closure inside for loop with var statements.

Var statements are not block scoped. This means when creating a function in first loop we are not creating function with numbers 0,1,2 but with variable i which is just a reference to what is last defined. So in second loop when we log function it will look for value of i and return the last defined value 3 each time it is logged.

You can remove this problem by using let keyword and IIFE(Immediately Invoked Function Expression)

Using let keyword:

You use ES6 let keyword to ensure that the code within for block runs as expected.

const funcs = [];
for (let i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("i value is " + i);
  }
}
for (var k = 0; k < 3; k++) {
  funcs[k]();
}
Output:

i value is 0

i value is 1

i value is 2

Using IIFE:

Another way to eliminate the above problem is to use immediately invoked function expression (IIFE), which forces immediate invocation of function as soon as the loop runs. Instead of stacking and waiting for the loop to finish the function runs as soon as the loop starts. This will result in our expected output.

const func = [];
for (var i = 0; i < 3; i++) {
  func[i] = (function(value) {
    console.log("i value is " + i);
  })(i);
}
Output:

i value is 0

i value is 1

i value is 2

Closure in JavaScript

The closure is an important concept in functional programming. Closure means that an inner function always has access to the vars and lets of outer function, even after the function has returned. It is a form of lexical scoping.

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). Before getting into closure, we need to know the following terms:

Scope:

A scope is created by a function or a code block. While defining a variable, we want to create some boundaries for variables. The accessibility of variables is within these boundaries (i.e) scope. Outside scope, the variable is inaccessible.

Example:
function f1(){
  //function scope
  let a = 2;
  console.log(a);
}
f1();
console.log(a); // outside scope Reference error
Output:

2

Reference error

When variable a is accessed within its function f1 it gets executed and returns 2. But when we try to access outside function it throws reference error.

Scope is a policy that rules the accessibility of variables.

Lexical Scope:

Lexical scope defines the scope of a variable by position of the variable declared in source code. Outer scope determined statically or at lexical time.

According to lexical scoping, the scopes can be nested and inner function can access variables declared outside.

Example:
let a = 2; // global variable
function f1(){
  let b = 3; // local variable
  console.log(a+b);
}
f1();
Output:

5

Now going to closure,

As we already know, closure means that an inner function always has access to the vars and parameters of its outer function, even after returned.

Example:

function f1(){

  //outer function

  let a=2;

  function f2(){

    //inner function

    console.log(a);

  }

  f2();

}

f1();

Output:

2

Now inner function can access outer variable even if it is executed separately.

function f1(){
  //outer function
  let a=2;
  function f2(){
    //inner function
    console.log(a);
  return f2();
}
var f3 = f1(); // function expression
f3;
Output:

2

Functions are first-class citizens in JavaScript. A function can return another function in JavaScript. A function which is assigned to a variable is called function expression.

Another important feature of closure is that outer variable keeps their state between multiple calls. But inner function does not keep separate copy of outer variable instead reference outer variable.

That means value of outer variable is changed if you change inner variable.

Example:

function f1(){

  //outer function

  var a=2;

  function f2(){

    //inner function

    return a+1;

  }

  return f2();

}

var f3 = f1(); // function expression

f3;

Output:

3

Closure is a function that access its lexical scope even executed outside of its lexical scope.

When to use closure?

Closure is an important concept in functional programming. Currying in functional programming is possible because of closure.

Currying is a process that allows you to transform a function with multiple arguments into a sequence of nesting functions. Instead of a function taking all arguments at one time, it takes the first one and returns a new function, which takes a second one and returns another function and so on.

Currying transforms f(a,b,c) into f(a) (b) (c).

Example:
function add(a) {

  return function executeadd(b) {

    return a + b;

  }

}

const sum = add(2);

sum(3);

sum(5);

const sum1 = add(3);

sum(4);
Output:

6

We will see about closure in loop in next part.

Async/await in JavaScript

Async/await is an extension of promise. We use async keyword with a function to represent that the function is asynchronous. The async function returns a promise. It is also possible to use await keyword inside a async function.

Javascript async keyword:
Syntax:
async function name(parameter1, parameter2, ...paramaterN) {
    // statements
}

name – name of function

parameter- parameter that are passed

Example:
// async function example

async function f() {
    console.log('Async function.');
    return Promise.resolve(1);
}
Output:

Async function.

Since async function returns a promise we can use chaining method then()

Async with promise chaining:
async function f() {
    console.log('Async function.');
    return Promise.resolve(1);
}

f().then(function(result) {
    console.log(result)
});
Output:

Async function.

1

In the example first f() function is resolved and then function gets executed.

JavaScript await keyword:

await keyword is used inside the async function to wait for asynchronous operation.

Syntax:

let result = await promise;

await pauses the asynchronous function till the promise returns a resolved or rejected value.

// a promise
let promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
    resolve('Promise resolved')}, 4000); 
});

// async function
async function asyncFunc() {

    // wait until the promise resolves 
    let result = await promise; 

    console.log(result);
    console.log('Hello');
}

// calling the async function
asyncFunc();
Output:

Promise resolved

Hello

Here first a promise object is created and it gets resolved after 4000 milliseconds. The async function waits for promise to resolve or reject and returns hello only after promise is complete.

The same program without await will print hello before resolving promise.

The async function helps to execute asynchronous methods in a synchronous way. This is helpful for multiple promises in a program.

let promise1; 
let promise2;
let promise3;

async function asyncFunc() {
    let result1 = await promise1;
    let result2 = await promise2;
    let result3 = await promise3;

    console.log(result1);
    console.log(result1);
    console.log(result1);
}
Error handling:
In async function we can use catch method to catch the errors.
asyncFunc().catch(
    // catch error and do something
)
We can also use try/catch,
// a promise
let promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
    resolve('Promise resolved')}, 4000); 
});

// async function
async function asyncFunc() {
    try {
        // wait until the promise resolves 
        let result = await promise; 

        console.log(result);
    }   

    catch(error) {
        console.log(error);
    }
}

// calling the async function
asyncFunc(); // Promise resolved

Output:

Promise resolved

Async/await is helpful in error handling, debugging and makes the code readable.

Supported Browsers: 
  • Google Chrome 55 and above
  • Firefox 52 and above
  • Apple Safari 10.1 and above
  • Opera 42 and above
  • Edge 14 and above