| No. | Questions |
|---|
| 401 | What is RxJS |
| 402 | What is the difference between Function constructor and function declaration |
| 403 | What is a Short circuit condition |
| 404 | What is the easiest way to resize an array |
| 405 | What is an observable |
| 406 | What is the difference between function and class declarations |
| 407 | What is an async function |
| 408 | How do you prevent promises swallowing errors |
| 409 | What is deno |
| 410 | How do you make an object iterable in javascript |
| 411 | What is a Proper Tail Call |
| 412 | How do you check an object is a promise or not |
| 413 | How to detect if a function is called as constructor |
| 414 | What are the differences between arguments object and rest parameter |
| 415 | What are the differences between spread operator and rest parameter |
| 416 | What are the different kinds of generators |
| 417 | What are the built-in iterables |
| 418 | What are the differences between for...of and for...in statements |
| 419 | How do you define instance and non-instance properties |
| 420 | What is the difference between isNaN and Number.isNaN? |
| 421 | How to invoke an IIFE without any extra brackets? |
| 422 | Is that possible to use expressions in switch cases? |
| 423 | What is the easiest way to ignore promise errors? |
| 424 | How do style the console output using CSS? |
| 425 | What is nullish coalescing operator (??)? |
| 426 | How do you group and nest console output? |
| 427 | What is the difference between dense and sparse arrays? |
| 428 | What are the different ways to create sparse arrays? |
| 429 | What is the difference between setTimeout, setImmediate and process.nextTick? |
| 430 | How do you reverse an array without modifying original array? |
| 431 | How do you create custom HTML element? |
| 432 | What is global execution context? |
| 433 | What is function execution context? |
| 434 | What is debouncing? |
| 435 | What is throttling? |
| 436 | What is optional chaining? |
| 437 | What is an environment record? |
| 438 | How to verify if a variable is an array? |
| 439 | What is pass by value and pass by reference? |
| 440 | What are the differences between primitives and non-primitives? |
| 441 | What are hidden classes? |
| 442 | What is inline caching? |
| 443 | How do you create your own bind method using either call or apply method? |
| 444 | What are the differences between pure and impure functions?
| 445 | What is referential transparency? |
| 446 | What are the possible side-effects in javascript? |
| 447 | What are compose and pipe functions? |
| 448 | What is module pattern? |
| 449 | What is Functon Composition? |
| 450 | How to use await outside of async function prior to ES2022? |
-
RxJS (Reactive Extensions for JavaScript) is a library for implementing reactive programming using observables that makes it easier to compose asynchronous or callback-based code. It also provides utility functions for creating and working with observables.
-
The functions which are created with
Function constructordo not create closures to their creation contexts but they are always created in the global scope. i.e, the function can access its own local variables and global scope variables only. Whereas function declarations can access outer function variables(closures) too.Let's see this difference with an example,
Function Constructor:
var a = 100; function createFunction() { var a = 200; return new Function("return a;"); } console.log(createFunction()()); // 100
Function declaration:
var a = 100; function createFunction() { var a = 200; return function func() { return a; }; } console.log(createFunction()()); // 200
-
Short circuit conditions are meant for condensed way of writing simple if statements. Let's demonstrate the scenario using an example. If you would like to login to a portal with an authentication condition, the expression would be as below,
if (authenticate) { loginToPorta(); }
Since the javascript logical operators evaluated from left to right, the above expression can be simplified using && logical operator
authenticate && loginToPorta();
-
The length property of an array is useful to resize or empty an array quickly. Let's apply length property on number array to resize the number of elements from 5 to 2,
var array = [1, 2, 3, 4, 5]; console.log(array.length); // 5 array.length = 2; console.log(array.length); // 2 console.log(array); // [1,2]
and the array can be emptied too
var array = [1, 2, 3, 4, 5]; array.length = 0; console.log(array.length); // 0 console.log(array); // []
-
An Observable is basically a function that can return a stream of values either synchronously or asynchronously to an observer over time. The consumer can get the value by calling
subscribe()method. Let's look at a simple example of an Observableimport { Observable } from "rxjs"; const observable = new Observable((observer) => { setTimeout(() => { observer.next("Message from a Observable!"); }, 3000); }); observable.subscribe((value) => console.log(value));
Note: Observables are not part of the JavaScript language yet but they are being proposed to be added to the language
-
The main difference between function declarations and class declarations is
hoisting. The function declarations are hoisted but not class declarations.Classes:
const user = new User(); // ReferenceError class User {}
Constructor Function:
const user = new User(); // No error function User() {}
-
An async function is a function declared with the
asynckeyword which enables asynchronous, promise-based behavior to be written in a cleaner style by avoiding promise chains. These functions can contain zero or moreawaitexpressions.Let's take a below async function example,
async function logger() { let data = await fetch("http://someapi.com/users"); // pause until fetch returns console.log(data); } logger();
It is basically syntax sugar over ES2015 promises and generators.
-
While using asynchronous code, JavaScript’s ES6 promises can make your life a lot easier without having callback pyramids and error handling on every second line. But Promises have some pitfalls and the biggest one is swallowing errors by default.
Let's say you expect to print an error to the console for all the below cases,
Promise.resolve("promised value").then(function () { throw new Error("error"); }); Promise.reject("error value").catch(function () { throw new Error("error"); }); new Promise(function (resolve, reject) { throw new Error("error"); });
But there are many modern JavaScript environments that won't print any errors. You can fix this problem in different ways,
-
Add catch block at the end of each chain: You can add catch block to the end of each of your promise chains
Promise.resolve("promised value") .then(function () { throw new Error("error"); }) .catch(function (error) { console.error(error.stack); });
But it is quite difficult to type for each promise chain and verbose too.
-
Add done method: You can replace first solution's then and catch blocks with done method
Promise.resolve("promised value").done(function () { throw new Error("error"); });
Let's say you want to fetch data using HTTP and later perform processing on the resulting data asynchronously. You can write
doneblock as below,getDataFromHttp() .then(function (result) { return processDataAsync(result); }) .done(function (processed) { displayData(processed); });
In future, if the processing library API changed to synchronous then you can remove
doneblock as below,getDataFromHttp().then(function (result) { return displayData(processDataAsync(result)); });
and then you forgot to add
doneblock tothenblock leads to silent errors. -
Extend ES6 Promises by Bluebird: Bluebird extends the ES6 Promises API to avoid the issue in the second solution. This library has a “default” onRejection handler which will print all errors from rejected Promises to stderr. After installation, you can process unhandled rejections
Promise.onPossiblyUnhandledRejection(function (error) { throw error; });
and discard a rejection, just handle it with an empty catch
Promise.reject("error value").catch(function () {});
-
-
Deno is a simple, modern and secure runtime for JavaScript and TypeScript that uses V8 JavaScript engine and the Rust programming language.
-
By default, plain objects are not iterable. But you can make the object iterable by defining a
Symbol.iteratorproperty on it.Let's demonstrate this with an example,
const collection = { one: 1, two: 2, three: 3, [Symbol.iterator]() { const values = Object.keys(this); let i = 0; return { next: () => { return { value: this[values[i++]], done: i > values.length, }; }, }; }, }; const iterator = collection[Symbol.iterator](); console.log(iterator.next()); // → {value: 1, done: false} console.log(iterator.next()); // → {value: 2, done: false} console.log(iterator.next()); // → {value: 3, done: false} console.log(iterator.next()); // → {value: undefined, done: true}
The above process can be simplified using a generator function,
const collection = { one: 1, two: 2, three: 3, [Symbol.iterator]: function* () { for (let key in this) { yield this[key]; } }, }; const iterator = collection[Symbol.iterator](); console.log(iterator.next()); // {value: 1, done: false} console.log(iterator.next()); // {value: 2, done: false} console.log(iterator.next()); // {value: 3, done: false} console.log(iterator.next()); // {value: undefined, done: true}
-
First, we should know about tail call before talking about "Proper Tail Call". A tail call is a subroutine or function call performed as the final action of a calling function. Whereas Proper tail call(PTC) is a technique where the program or code will not create additional stack frames for a recursion when the function call is a tail call.
For example, the below classic or head recursion of factorial function relies on stack for each step. Each step need to be processed upto
n * factorial(n - 1)function factorial(n) { if (n === 0) { return 1; } return n * factorial(n - 1); } console.log(factorial(5)); //120
But if you use Tail recursion functions, they keep passing all the necessary data it needs down the recursion without relying on the stack.
function factorial(n, acc = 1) { if (n === 0) { return acc; } return factorial(n - 1, n * acc); } console.log(factorial(5)); //120
The above pattern returns the same output as the first one. But the accumulator keeps track of total as an argument without using stack memory on recursive calls.
-
If you don't know if a value is a promise or not, wrapping the value as
Promise.resolve(value)which returns a promisefunction isPromise(object) { if (Promise && Promise.resolve) { return Promise.resolve(object) == object; } else { throw "Promise not supported in your environment"; } } var i = 1; var promise = new Promise(function (resolve, reject) { resolve(); }); console.log(isPromise(i)); // false console.log(isPromise(promise)); // true
Another way is to check for
.then()handler typefunction isPromise(value) { return Boolean(value && typeof value.then === "function"); } var i = 1; var promise = new Promise(function (resolve, reject) { resolve(); }); console.log(isPromise(i)); // false console.log(isPromise(promise)); // true
-
You can use
new.targetpseudo-property to detect whether a function was called as a constructor(using the new operator) or as a regular function call.- If a constructor or function invoked using the new operator, new.target returns a reference to the constructor or function.
- For function calls, new.target is undefined.
function Myfunc() { if (new.target) { console.log('called with new'); } else { console.log('not called with new'); } } new Myfunc(); // called with new Myfunc(); // not called with new Myfunc.call({}); // not called with new
-
There are three main differences between arguments object and rest parameters
- The arguments object is an array-like but not an array. Whereas the rest parameters are array instances.
- The arguments object does not support methods such as sort, map, forEach, or pop. Whereas these methods can be used in rest parameters.
- The rest parameters are only the ones that haven’t been given a separate name, while the arguments object contains all arguments passed to the function
-
Rest parameter collects all remaining elements into an array. Whereas Spread operator allows iterables( arrays / objects / strings ) to be expanded into single arguments/elements. i.e, Rest parameter is opposite to the spread operator.
-
There are five kinds of generators,
-
Generator function declaration:
function* myGenFunc() { yield 1; yield 2; yield 3; } const genObj = myGenFunc();
-
Generator function expressions:
const myGenFunc = function* () { yield 1; yield 2; yield 3; }; const genObj = myGenFunc();
-
Generator method definitions in object literals:
const myObj = { *myGeneratorMethod() { yield 1; yield 2; yield 3; }, }; const genObj = myObj.myGeneratorMethod();
-
Generator method definitions in class:
class MyClass { *myGeneratorMethod() { yield 1; yield 2; yield 3; } } const myObject = new MyClass(); const genObj = myObject.myGeneratorMethod();
-
Generator as a computed property:
const SomeObj = { *[Symbol.iterator]() { yield 1; yield 2; yield 3; }, }; console.log(Array.from(SomeObj)); // [ 1, 2, 3 ]
-
-
Below are the list of built-in iterables in javascript,
- Arrays and TypedArrays
- Strings: Iterate over each character or Unicode code-points
- Maps: iterate over its key-value pairs
- Sets: iterates over their elements
- arguments: An array-like special variable in functions
- DOM collection such as NodeList
-
Both for...in and for...of statements iterate over js data structures. The only difference is over what they iterate:
- for..in iterates over all enumerable property keys of an object
- for..of iterates over the values of an iterable object.
Let's explain this difference with an example,
let arr = ["a", "b", "c"]; arr.newProp = "newVlue"; // key are the property keys for (let key in arr) { console.log(key); // 0, 1, 2 & newValue } // value are the property values for (let value of arr) { console.log(value); // a, b, c }
Since for..in loop iterates over the keys of the object, the first loop logs 0, 1, 2 and newProp while iterating over the array object. The for..of loop iterates over the values of a arr data structure and logs a, b, c in the console.
-
The Instance properties must be defined inside of class methods. For example, name and age properties defined inside constructor as below,
class Person { constructor(name, age) { this.name = name; this.age = age; } }
But Static(class) and prototype data properties must be defined outside of the ClassBody declaration. Let's assign the age value for Person class as below,
Person.staticAge = 30; Person.prototype.prototypeAge = 40;
-
- isNaN: The global function
isNaNconverts the argument to a Number and returns true if the resulting value is NaN. - Number.isNaN: This method does not convert the argument. But it returns true when the type is a Number and value is NaN.
Let's see the difference with an example,
isNaN(‘hello’); // true Number.isNaN('hello'); // false
- isNaN: The global function
-
Immediately Invoked Function Expressions(IIFE) requires a pair of parenthesis to wrap the function which contains set of statements.
(function (dt) { console.log(dt.toLocaleTimeString()); })(new Date());
Since both IIFE and void operator discard the result of an expression, you can avoid the extra brackets using
void operatorfor IIFE as below,void function (dt) { console.log(dt.toLocaleTimeString()); }(new Date());
-
You might have seen expressions used in switch condition but it is also possible to use for switch cases by assigning true value for the switch condition. Let's see the weather condition based on temparature as an example,
const weather = (function getWeather(temp) { switch (true) { case temp < 0: return "freezing"; case temp < 10: return "cold"; case temp < 24: return "cool"; default: return "unknown"; } })(10);
-
The easiest and safest way to ignore promise errors is void that error. This approach is ESLint friendly too.
await promise.catch((e) => void e);
-
You can add CSS styling to the console output using the CSS format content specifier %c. The console string message can be appended after the specifier and CSS style in another argument. Let's print the red the color text using console.log and CSS specifier as below,
console.log("%cThis is a red text", "color:red");
It is also possible to add more styles for the content. For example, the font-size can be modified for the above text
console.log( "%cThis is a red text with bigger font", "color:red; font-size:20px" );
-
It is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, and otherwise returns its left-hand side operand. This can be contrasted with the logical OR (||) operator, which returns the right-hand side operand if the left operand is any falsy value, not only null or undefined.
console.log(null ?? true); // true console.log(false ?? true); // false console.log(undefined ?? true); // true
-
The
console.group()can be used to group related log messages to be able to easily read the logs and use console.groupEnd()to close the group. Along with this, you can also nest groups which allows to output message in hierarchical manner.For example, if you’re logging a user’s details:
console.group("User Details"); console.log("name: Sudheer Jonna"); console.log("job: Software Developer"); // Nested Group console.group("Address"); console.log("Street: Commonwealth"); console.log("City: Los Angeles"); console.log("State: California"); // Close nested group console.groupEnd(); // Close outer group console.groupEnd()
You can also use
console.groupCollapsed()instead ofconsole.group()if you want the groups to be collapsed by default. -
An array contains items at each index starting from first(0) to last(array.length - 1) is called as Dense array. Whereas if at least one item is missing at any index, the array is called as sparse.
Let's see the below two kind of arrays,
const avengers = ["Ironman", "Hulk", "CaptainAmerica"]; console.log(avengers[0]); // 'Ironman' console.log(avengers[1]); // 'Hulk' console.log(avengers[2]); // 'CaptainAmerica' console.log(avengers.length); // 3 const justiceLeague = ["Superman", "Aquaman", , "Batman"]; console.log(justiceLeague[0]); // 'Superman' console.log(justiceLeague[1]); // 'Aquaman' console.log(justiceLeague[2]); // undefined console.log(justiceLeague[3]); // 'Batman' console.log(justiceLeague.length); // 4
-
There are 4 different ways to create sparse arrays in JavaScript
- Array literal: Omit a value when using the array literal
const justiceLeague = ["Superman", "Aquaman", , "Batman"]; console.log(justiceLeague); // ['Superman', 'Aquaman', empty ,'Batman']
- Array() constructor: Invoking Array(length) or new Array(length)
const array = Array(3); console.log(array); // [empty, empty ,empty]
- Delete operator: Using delete array[index] operator on the array
const justiceLeague = ["Superman", "Aquaman", "Batman"]; delete justiceLeague[1]; console.log(justiceLeague); // ['Superman', empty, ,'Batman']
- Increase length property: Increasing length property of an array
const justiceLeague = ['Superman', 'Aquaman', 'Batman']; justiceLeague.length = 5; console.log(justiceLeague); // ['Superman', 'Aquaman', 'Batman', empty, empty]
- Array literal: Omit a value when using the array literal
-
- Set Timeout: setTimeout() is to schedule execution of a one-time callback after delay milliseconds.
- Set Immediate: The setImmediate function is used to execute a function right after the current event loop finishes.
- Process NextTick: If process.nextTick() is called in a given phase, all the callbacks passed to process.nextTick() will be resolved before the event loop continues. This will block the event loop and create I/O Starvation if process.nextTick() is called recursively.
-
The
reverse()method reverses the order of the elements in an array but it mutates the original array. Let's take a simple example to demonistrate this case,const originalArray = [1, 2, 3, 4, 5]; const newArray = originalArray.reverse(); console.log(newArray); // [ 5, 4, 3, 2, 1] console.log(originalArray); // [ 5, 4, 3, 2, 1]
There are few solutions that won't mutate the original array. Let's take a look.
-
Using slice and reverse methods: In this case, just invoke the
slice()method on the array to create a shallow copy followed byreverse()method call on the copy.const originalArray = [1, 2, 3, 4, 5]; const newArray = originalArray.slice().reverse(); //Slice an array gives a new copy console.log(originalArray); // [1, 2, 3, 4, 5] console.log(newArray); // [ 5, 4, 3, 2, 1]
-
Using spread and reverse methods: In this case, let's use the spread syntax (...) to create a copy of the array followed by
reverse()method call on the copy.const originalArray = [1, 2, 3, 4, 5]; const newArray = [...originalArray].reverse(); console.log(originalArray); // [1, 2, 3, 4, 5] console.log(newArray); // [ 5, 4, 3, 2, 1]
-
Using reduce and spread methods: Here execute a reducer function on an array elements and append the accumulated array on right side using spread syntax
const originalArray = [1, 2, 3, 4, 5]; const newArray = originalArray.reduce((accumulator, value) => { return [value, ...accumulator]; }, []); console.log(originalArray); // [1, 2, 3, 4, 5] console.log(newArray); // [ 5, 4, 3, 2, 1]
-
Using reduceRight and spread methods: Here execute a right reducer function(i.e. opposite direction of reduce method) on an array elements and append the accumulated array on left side using spread syntax
const originalArray = [1, 2, 3, 4, 5]; const newArray = originalArray.reduceRight((accumulator, value) => { return [...accumulator, value]; }, []); console.log(originalArray); // [1, 2, 3, 4, 5] console.log(newArray); // [ 5, 4, 3, 2, 1]
-
Using reduceRight and push methods: Here execute a right reducer function(i.e. opposite direction of reduce method) on an array elements and push the iterated value to the accumulator
const originalArray = [1, 2, 3, 4, 5]; const newArray = originalArray.reduceRight((accumulator, value) => { accumulator.push(value); return accumulator; }, []); console.log(originalArray); // [1, 2, 3, 4, 5] console.log(newArray); // [ 5, 4, 3, 2, 1]
-
-
The creation of custom HTML elements involves two main steps,
- Define your custom HTML element: First you need to define some custom class by extending HTMLElement class.
After that define your component properties (styles,text etc) using
connectedCallbackmethod. Note: The browser exposes a function calledcustomElements.defineinorder to reuse the element.class CustomElement extends HTMLElement { connectedCallback() { this.innerHTML = "This is a custom element"; } } customElements.define("custom-element", CustomElement);
- Use custome element just like other HTML element: Declare your custom element as a HTML tag.
<body> <custom-element> </body>
- Define your custom HTML element: First you need to define some custom class by extending HTMLElement class.
After that define your component properties (styles,text etc) using
-
The global execution context is the default or first execution context that is created by the JavaScript engine before any code is executed(i.e, when the file first loads in the browser). All the global code that is not inside a function or object will be executed inside this global execution context. Since JS engine is single threaded there will be only one global environment and there will be only one global execution context.
For example, the below code other than code inside any function or object is executed inside the global execution context.
var x = 10; function A() { console.log("Start function A"); function B() { console.log("In function B"); } B(); } A(); console.log("GlobalContext");
-
Whenever a function is invoked, the JavaScript engine creates a different type of Execution Context known as a Function Execution Context (FEC) within the Global Execution Context (GEC) to evaluate and execute the code within that function.
-
Debouncing is a programming pattern that allows delaying execution of some piece of code until a specified time to avoid unnecessary CPU cycles, API calls and improve performance. The debounce function make sure that your code is only triggered once per user input. The common usecases are Search box suggestions, text-field auto-saves, and eliminating double-button clicks.
Let's say you want to show suggestions for a search query, but only after a visitor has finished typing it. So here you write a debounce function where the user keeps writing the characters with in 500ms then previous timer cleared out using
clearTimeoutand reschedule API call/DB query for a new time—300 ms in the future.function debounce(func, timeout = 500) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, args); }, timeout); }; } function fetchResults() { console.log("Fetching input suggestions"); } const processChange = debounce(() => fetchResults());
The debounce() function can be used on input, button and window events
Input:
<input type="text" onkeyup="processChange()" />
Button:
<button onclick="processChange()">Click me</button>
Windows event:
window.addEventListener("scroll", processChange); -
Throttling is a technique used to limit the execution of an event handler function, even when this event triggers continuously due to user actions. The common use cases are browser resizing, window scrolling etc.
The below example creates a throttle function to reduce the number of events for each pixel change and trigger scroll event for each 100ms except for the first event.
const throttle = (func, limit) => { let inThrottle; return (...args) => { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => (inThrottle = false), limit); } }; }; window.addEventListener("scroll", () => { throttle(handleScrollAnimation, 100); });
-
According to MDN official docs, the optional chaining operator (?.) permits reading the value of a property located deep within a chain of connected objects without having to expressly validate that each reference in the chain is valid.
The ?. operator is like the . chaining operator, except that instead of causing an error if a reference is nullish (null or undefined), the expression short-circuits with a return value of undefined. When used with function calls, it returns undefined if the given function does not exist.
const adventurer = { name: 'Alice', cat: { name: 'Dinah' } }; const dogName = adventurer.dog?.name; console.log(dogName); // expected output: undefined console.log(adventurer.someNonExistentMethod?.()); // expected output: undefined
-
According to ECMAScript specification 262 (9.1):
Environment Record is a specification type used to define the association of Identifiers to specific variables and functions, based upon the lexical nesting structure of ECMAScript code.
Usually an Environment Record is associated with some specific syntactic structure of ECMAScript code such as a FunctionDeclaration, a BlockStatement, or a Catch clause of a TryStatement.
Each time such code is evaluated, a new Environment Record is created to record the identifier bindings that are created by that code.
-
It is possible to check if a variable is an array instance using 3 different ways,
-
Array.isArray() method:
The
Array.isArray(value)utility function is used to determine whether value is an array or not. This function returns a true boolean value if the variable is an array and a false value if it is not.const numbers = [1, 2, 3]; const user = { name: 'John' }; Array.isArray(numbers); // true Array.isArray(user); //false
-
instanceof operator:
The instanceof operator is used to check the type of an array at run time. It returns true if the type of a variable is an Array other false for other type.
const numbers = [1, 2, 3]; const user = { name: 'John' }; console.log(numbers instanceof Array); // true console.log(user instanceof Array); // false
-
Checking constructor type:
The constructor property of the variable is used to determine whether the variable Array type or not.
const numbers = [1, 2, 3]; const user = { name: 'John' }; console.log(numbers.constructor === Array); // true console.log(user.constructor === Array); // false
-
-
Pass-by-value creates a new space in memory and makes a copy of a value. Primitives such as string, number, boolean etc will actually create a new copy. Hence, updating one value doesn't impact the other value. i.e, The values are independent of each other.
let a = 5; let b = a; b++; console.log(a, b); //5, 6
In the above code snippet, the value of
ais assigned toband the variablebhas been incremented. Since there is a new space created for variableb, any update on this variable doesn't impact the variablea.Pass by reference doesn't create a new space in memory but the new variable adopts a memory address of an initial variable. Non-primitives such as objects, arrays and functions gets the reference of the initiable variable. i.e, updating one value will impact the other variable.
let user1 = { name: 'John', age: 27 }; let user2 = user1; user2.age = 30; console.log(user1.age, user2.age); // 30, 30
In the above code snippet, updating the
ageproperty of one object will impact the other property due to the same reference. -
JavaScript language has both primitives and non-primitives but there are few differences between them as below,
Primitives Non-primitives These types are predefined Created by developer These are immutable Mutable Compare by value Compare by reference Stored in Stack Stored in heap Contain certain value Can contain NULL too -
The custom bind function needs to be created on Function prototype inorder to use it as other builtin functions. This custom function should return a function similar to original bind method and the implementation of inner function needs to use apply method call.
The function which is going to bind using custom
myOwnBindmethod act as the attached function(boundTargetFunction) and argument as the object forapplymethod call.Function.prototype.myOwnBind = function(whoIsCallingMe) { if (typeof this !== "function") { throw new Error(this + "cannot be bound as it's not callable"); } const boundTargetFunction = this; return function() { boundTargetFunction.apply(whoIsCallingMe, arguments); } }
-
Some of the major differences between pure and impure function are as below,
| Pure function | Impure function |
|---|---|
| It has no side effects | It causes side effects |
| It is always return the same result | It returns different result on each call |
| Easy to read and debug | Difficult to read and debug because they are affected by extenal code |
An expression in javascript can be replaced by its value without affecting the behaviour of the program is called referential transparency. Pure functions are referentially transparent.
const add = (x,y) => x + y;
const multiplyBy2 = (x) => x * 2;
//Now add (2, 3) can be replaced by 5.
multiplyBy2(add(2, 3)); A side effect is the modification of state through the invocation of a function or expression. These side effects makes our function impure by default. Below are some side effects which makes function impure,
- Making an HTTP request. Asynchronous functions such as fetch and promise are impure.
- DOM manipulations
- Mutating the input data
- Printing to a screen or console: For example, console.log() and alert()
- Fetching the current time
- Math.random() calls: Modifies the internal state of Math object
-
The "compose" and "pipe" are two techniques commonly used in functional programming to simplify complex operations and make code more readable. They are not native in JavaScript and higher order functions. the
compose()applies right to left any number of functions to the output of the previous function. -
Module pattern is a designed pattern used to wrap a set of variables and functions together in a single scope returned as an object. JavaScript doesn't have access specifiers similar to other languages(Java, Pythong etc) to provide private scope. It uses IIFE (Immediately invoked function expression) to allow for private scopes. i.e, a closure that protect variables and methods.
The module pattern look like below,
(function() { // Private variables or functions goes here. return { // Return public variables or functions here. } })();
Let's see an example of module pattern for an employee with private and public access,
const createEmployee = (function () { // Private const name = "John"; const department = "Sales"; const getEmployeeName = () => name; const getDepartmentName = () => department; // Public return { name, department, getName: () => getEmployeeName(), getDepartment: () => getDepartmentName(), }; })(); console.log(createEmployee.name); console.log(createEmployee.department); console.log(createEmployee.getName()); console.log(createEmployee.getDepartment());
Note: It mimic the concepts of classes with private variables and methods.
-
It is an approach where the result of one function is passed on to the next function, which is passed to another until the final function is executed for the final result.
//example const double = x => x * 2 const square = x => x * x var output1 = double(2); var output2 = square(output1); console.log(output2); var output_final = square(double(2)); console.log(output_final);
-
Prior to ES2022, if you attempted to use an await outside of an async function resulted in a SyntaxError.
await Promise.resolve(console.log('Hello await')); // SyntaxError: await is only valid in async function
But you can fix this issue with an alternative IIFE (Immediately Invoked Function Expression) to get access to the feature.
(async function() { await Promise.resolve(console.log('Hello await')); // Hello await }());
In ES2022, you can write top-level await without writing any hacks.
await Promise.resolve(console.log('Hello await')); //Hello await
