
Topics covered:
1. What is “this”?
The “this” is a reserved keyword in javascript. We are not allowed to use “this” as an identifier. “this” keyword changes its behaviour according to the use-case.
Strict mode set “this” keyword context undefined. But we have an alternative to change its context by using call, apply, and bind functions.
“this” behaviour with Call, Apply, and Bind
call, apply, and bind functions commonly are used to change the context of this keyword, or this behaviour helps to build a more generic function.
const myName = "Hyy";
// Function that logs the name property of 'this' object
function printName() {
'use strict';
console.log(this.name);
}
// Object with a name property
const person = {
name: "Arya"
};
// Calling the printName function with 'person' object as context using call
printName.call(person); // Output: Arya
// Calling the printName function with 'person' object as context using apply
printName.apply(person); // Output: Arya
// Calling the printName function without a specified context (this will throw an error)
printName(); // Output: Cannot read properties of undefined (reading 'name')
The difference between call and apply is that call expects the parameters as individual arguments whereas apply expects parameters as an array.
bind changes the context of “this” and returns a new function. It does not execute the function right away like call and apply.
“this” behaviour with Functions
Function definition by using Arrow function style, Where this keyword refers to the closest context or empty/undefined.
Function definition by using the function keyword, Where this keyword refers to the global context or parent.
2. Closures
A closure is a feature in JavaScript where returned function has access to the outer function variables and properties in the scope chain.
function foo() {
var name = "Nick";
// Return a new function that logs the 'name' variable
return function() {
console.log(name);
};
}
// Currying: Calling the outer function foo() first returns an inner function,
// then calling the inner function using () logs the value of 'name'.
foo()(); // Output: Nick
3. Asynchronous JavaScript
Function running in parallel with some other processes is known as asynchronous. Asynchronous Javascript leverages asynchronous computation.
var foo = new Promise((resolve, reject) => {
if(true) {
resolve
} else {
reject
}
})2. Async-Await
Async-await is another way to enable asynchronous computation in JavaScript. Async-await works similarly to promises and they are implemented by using promises. We use async-await only because of its elegant and simple syntax and it won’t create callback hell(nested promises).
3. Generators
In JavaScript, a regular function is executed based on the run-to-completion model. It cannot pause midway and then continues from where it has paused.
A generator can pause midway and then continues from where it has paused.
The generator object is iterable and we use the next function and yield keyword to archive generator nature.
4. Hoisting and TDZ
console.log(foo); // undefined (Hoisted)
console.log(bar()) // bar (Hoisted)
var foo = "foo";
console.log(foo); // foo
function bar() {
return "bar";
}console.log(foo) // ReferenceError: Cannot access 'foo' before initialization "TDZ"
console.log(bar) // ReferenceError: Cannot access 'foo' before initialization "TDZ"
let foo = "foo";
const bar = "bar";
console.log(foo) // foo
console.log(bar) // bar5. Function Currying and Callbacks
Currying is a process to transform a function with multiple arguments into a sequence of nesting function calls. It returns a new function that expects the next argument inline.
The first-class function feature enables the callbacks. A callback function is a function passed into another function as an argument, which will be invoked inside the outer function to complete a certain action.
function simpleFunction(param1, param2, param3, …..) => function curriedFunction(param1)(param2)(param3)(….)
function calculateVolume(length) {
return function (breadth) {
return function (height) {
return length * breadth * height;
}
}
}
console.log(calculateVolume(4)(5)(6)); // 1206. Higher-Order Function
Higher-order functions accept a function or series of functions as an argument and return a function. The returned function may consist of some of the additional properties or constant for further computations.
//Assign a function to a variable originalFunc
const originalFunc = (num) => { return num + 2 };
//Re-assign the function to a new variable newFunc
const newFunc = originalFunc;
//Access the function's name property
newFunc.name; //'originalFunc'
//Return the function's body as a string
newFunc.toString(); //'(num) => { return num + 2 }'
//Add our own isMathFunction property to the function
newFunc.isMathFunction = true;
//Pass the function as an argument
const functionNameLength = (func) => { return func.name.length };
functionNameLength(originalFunc); //12
//Return the function
const returnFunc = () => { return newFunc };
returnFunc(); //[Function: originalFunc]