Concepts of Javascript — Part 2

Image for post
Image for post

📄 Table of Contents

▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ ✦ ✦ ✦ ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬

◉ Functional Programming

In functional programming, we think and code in terms of functions.

In most simplest term, Functional Programming is a form of programming in which you can pass functions as parameters to other functions and also return them as values.

In functional programming, closures are frequently used for partial application & currying.

Concepts of functional programming:

  • Pure functions
  • Recursion
  • Immutability (Variables are Immutable)
  • Functions are First-Class and can be Higher-Order
  • Referential transparency

◉ First-Class Functions

If you have been learning JavaScript, you may have heard that JavaScript treats functions as first-class citizens. That’s because in JavaScript or any other functional programming languages functions are objects.

In JavaScript functions are a special type of objects.They are Function objects. For example:

function greeting() {
console.log('Hello World');
}
// Invoking the function
greeting(); // prints 'Hello World'

To prove functions are objects in JavaScript, we could do something like this:

// We can add properties to functions like we do with objectsgreeting.lang = 'English';
console.log(greeting.lang); // Prints 'English'

Note — While this is perfectly valid in JavaScript, this is considered a harmful practice. You should not add random properties to the function objects, use an object if you have to.

In JavaScript, everything you can do with other types like object, string, or number, you can do with functions. You can pass them as parameters to other functions (callbacks), assign them to variables and pass them around etc. This is why functions in JavaScript are known as First-Class Functions.

◉ Higher-Order Functions

A Higher-Order function is a function that receives a function as an argument OR returns the function as output.

For example, Array.prototype.map, Array.prototype.filter and Array.prototype.reduce are some of the Higher-Order functions built into the language.

◉ Pure Functions

A pure function is independent of any state, or data change during a program’s execution. It must only depend on its input.

Pure functions are functions:-

  • Given the same input, will always return the same output.
  • Its output or return value must depend on the input/arguments.
  • pure functions must return a value.
  • Produces NO side effects, which means that it can’t alter any external state.

Examples:-

Math.max(2, 8, 5);        # 8const double = x => x * 2;Math.random();  # is NOT a pure function, WHY ? Even though we didn’t pass any arguments into any of the function calls, they all produced different output, meaning that `Math.random()` is not pure.

Let’s understand pure function with an example.

Below is a simple greeting function that takes the name of the person as input.

const greeting = "Hello";
const greet = person => `${greeting} ${person}!`;
console.log(greet("Ashmit")); // "Hello Ashmit!"

You may think that this will give the same output on the same input every time! Yes, that’s correct!

But it is not independent of whatever is happening outside the function. If we change the variable ‘greeting’ to “Howdy” the output will change even if we didn’t change the input to the ‘greet’ function.

const greeting = "Howdy";
const greet = person => `${greeting} ${person}!`;
console.log(greet("Ashmit")); // "Howdy Ashmit!"

A pure function should be independent of any external mutable state. It should only depend on its input. The above scenario is making our function impure because of its interaction with the outside mutable world, which is referred to as a Side Effect.

Let’s see in detail what the side effects actually mean with respect to pure functions.

Side Effect

A side effect is any interaction with the outside world from within a function. That could be anything from changing a variable that exists outside the function or calling another method from within a function to accessing a variable from outside the function.

Note: If a pure function calls a pure function this isn’t a side effect and the calling function is still pure.

Let’s make the impure ‘greet’ function pure, with a slight modification. We know that pure function should only be dependent on the inputs and should work the same even if the outside world is on fire. So we’ll do exactly that,

const greeting = "Hello";
const greet = (greeting, person) => `${greeting} ${person}!`;
console.log(greet(greeting, "Ashmit"));// "Hello Ashmit!"

Now our function ‘greet’ is pure as it only depends on its inputs. It will always give the same output with the same input.

Benefits of Pure functions

  • The outputs of pure functions can be memoized as they will always give the same output for the same input. This proves very helpful in Dynamic Programming where optimal substructure is a must.
  • Pure functions are immediately testable once created and are also helpful in maintaining and refactoring code.

One very important and use-case of pure functions is in Redux ( State management for ReactJS ). The reducers must always be pure functions because reducers perform actions on the state. If reducers are impure for the same state of actions on the state of an application, it will yield different results and hence will fail its purpose!

Pure Functions have a huge performance impact during execution on the Browser. How ?

Picture a scenario where a specific Pure Function is getting called multiple times. The Application calls for the same function multiple times with the same parameters — assume “add(10, 20)”. After executing it multiple times, the Chrome V8 Engine tries to optimise the code further by storing the execution result of the following function call.

On the next call to the same function, with the same parameter, instead of executing the function again, the cached result is returned. Hence enhancing the Application Performance.

◉ Arrow functions vs Regular functions

  • short and concise Syntax
  • Use of this keyword ❌
  • Availability of arguments objects ❌
  • Using new keyword ❌
Image for post
Image for post
arguments & new NOT allowed in Arrow functions.

You cannot rebind this in an arrow function. It will always be defined as the context in which it was defined. If you require this to be meaningful you should use a normal function.

◉ Currying

Is a technique for converting function calls with N arguments into chains of N function calls with a single argument for each function call?

Currying always returns another function with only one argument until all of the arguments have been applied. So, we just keep calling the returned function until we’ve exhausted all the arguments and the final value gets returned.

Note:

Curry takes a binary function and returns a unary function that returns a unary function.

A curried functions have a built-in iterator behaviour. One argument is applied at once which is then returned to the calling function to be used for next step.

🔹 Usages

  1. The common use-case for curried function are function composition.e.g., p(x) = q(r(x)). i.e building the new function from old function by passing arguments. Function q takes the return value as an argument from function r . Since, a function can only return one value, the function being applied to the return value must be unary.
  2. Ramda.js lib. functions are automatically curried and lodash has a function called curry which can be used to form curry function.
  3. Memoization is another good use case for curry function.
  4. Can create First class functions which means that we can use functions as arguments and return values.

🔘 Partial Application

Is a technique of fixing a number of arguments to a function, producing another function of smaller arguments i.e binding values to one or more of those arguments as the chain of function progressed.

JavaScript has the built-in method .bind that works on functions with any number of arguments and can bind an arbitrary amount of parameters. Its invocation has the following syntax.

.bind turns function into a new function.

🔘 Difference

  • Currying always produces nested unary (1-ary) functions. The transformed function is still largely the same as the original.
  • Partial application produces functions of arbitrary number of arguments. The transformed function is different from the original — it needs less arguments.
  • Currying is not partial application. It can be implemented using partial application. You can’t curry a function that takes any number of arguments, (unless you fix the number of arguments).

Reference(s):

◉ Memoization

It is a optimisation technique used to store the function calls in object and return the cached result when the same input is passed again. It is a process of caching results when we provide the same big inputs and return same output without heavy computations. Lets take an example

Image for post
Image for post

In the above example we are trying to square the number. So we have created an object square.cache where we will storing as key value pair. Line 2 we are checking in cache object for that particular key. If it is not present we will compute it and store it in square.cache object. If the key exists it won’t compute and what ever it is already stored in cache same it will return.

◉ Closures

In JS, variables defined outside a function are automatically available inside the function (but NOT vice versa) because JS uses “Lexical Scoping” & it achieves so using Closures (or inner functions).

  • In JavaScript, all functions work like closures which literally means closures are created every time a function is created, at function creation time.
  • Also defining a function inside another function (nested functions) and exposing it acts as a Closures. To expose a function, return it or pass it to another function.

The inner function will have access to the variables in the outer function scope, even after the outer function has returned.

However, a function doesn’t have to return in order to be called a CLOSURE. Simply accessing variables outside of your immediate lexical scope creates a CLOSURE.

Generally, in C & most other languages, after a function returns, all the local variables are NO longer accessible because the stack-frame is destroyed. But here we are calling the function X() (1st /2nd time), even after we have already returned from outer().

🔹 But, why to use Closures at all ?

  • Information-hiding (data privacy)
  • When binding event handlers to element
  • Callbacks

Closures are frequently used in JavaScript for object data privacy, in event handlers and callback functions, and in partial applications, currying, and other functional programming patterns.Among above things, closures are commonly used to give objects data privacy.

When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods. In JavaScript, any exposed method defined within the closure scope is privileged. For example:

const getSecret = (secret) => {
return {
get: () => secret
};
};

In the example above, the `.get()` method is defined inside the scope of `getSecret()`, which gives it access to any variables from `getSecret()`, and makes it a privileged method. In this case, the parameter, `secret`.

Objects are not the only way to produce data privacy. Closures can also be used to create stateful functions whose return values may be influenced by their internal state.

In functional programming, closures are frequently used for partial application & currying.

🔹 Disadvantages of using Closures in javascript.

[1]. As long as closures are active, this memory cannot be garbage collected, hence if not used properly can lead to ‘memory leaks’.

In JavaScript, when a function finishes executing, any variables declared within its body is “garbage collected”. In other words, it is deleted from memory. This is why local variables are possible in JavaScript. This is why variables inside functions cannot be accessed outside.

// dev is NOT accessible herefunction someFunc() {
// dev is accessible here
const dev = 'to';
}
// dev is NOT accessible here

Special exceptions occur when something inside the function depends on the variable being deleted. For example, the function below returns another function that depends on the variables of the parent function.

// Parent functionfunction parent() {
// Local variable of the parent function
const prefix = 'I am a ';
// Child function
return function(noun) {
// The child function depends on the variables of the parent function.
return prefix + noun;
};
}

NOTE: The example above takes advantage of a concept in functional programming called currying. You can read more about it if you want.

// Store the returned child function
const getSentence = parent();
// At this point, `parent()` has finished executing.
// Despite that, the `prefix` variable is still
// accessible to the child function. More on that later.
const job = getSentence('programmer');// What is the value of `job`?
console.log(job); // 'I am a programmer'

In this case, prefix is still usable by the child function even after it has been garbage collected because the child function created its own closure.

A closure is like a "snapshot" of the environment a function is in when it is executed. Its closure is its own internal copy of the environment.

Technically speaking, any variable in a closure is exclusively accessible to the child function that owns it. Operations can only be performed on these variables if the current execution context has a reference to the closure. In this case, the “snapshot” that the child function owns is the reference to that closure, therefore it has access to its variables.

When the parent function finished executing, the prefix variable is scheduled to be deleted. However, before that can be done, the child function "takes a snapshot" of its current environment (which includes all of the variables of the parent function it depends on). The child function now has its own copy of the prefix variable that it can access and manipulate. This is what closures are in its most basic use case. MDN provides a more technical definition.

So to fix this in your program if there comes a point that you’re done using an element inside the closure then you need to set it to null.

[2].creating functions inside other functions lead to duplication in memory consuming more momory, potentially slowing down the application.

🔹 Alternative of Closures ?

Unless you need privacy, it’s more practical to use the module pattern to create new objects with shared methods.

◉ Memory Leak in JS

Memory leak can be defined as a memory which is no more required by the application but has NOT been released so far.

[1]. Accidental global variable.

[2]. In case of Closures

[3]. Lingering DOM references to Removed Elements

It is important to note that, the local variable “outer of the outer function(parent) exists even after the outer function has returned, as the inner function child holds the reference to the outer function variable “outer, so the variable “outer” will not be garbage collected. Whereas in regular functions, when the function returns, its local variables no longer exists.

In such case, we need to release the memory explicitly by assigning null to the variables.

result = null;

source: https://dev.to/somedood/emulating-private-variables-in-javascript-with-closures-and-factory-functions-2314

◉ Garbage Collector in JS

The garbage collector works by keeping track of which objects are reachable by your code. The idea is that if an object is not reachable, the block of memory it occupies can be freed without breaking your program.

One way in which an object can be reached is if it’s assigned to a variable. Assigning a new value to a variable that presently points to an object (e.g. by assigning null to a) will reduce the reference count on that object by one. When this or any object's reference count is reduced to zero, it will qualify for garbage collection.

All that said, it’s not really important what value you use to replace the value of a variable, as long as it’s not some other object that would otherwise be garbage collected. For this reason, both undefined and null will work.

var info = {name: "anil", age: 25, status: "coder"};
info.name = undefined / null;
console.log(info);
Image for post
Image for post

For vs forEach() vs for/in vs for/of in for looping

source: https://thecodebarbarian.com/for-vs-for-each-vs-for-in-vs-for-of-in-javascript

There’s numerous ways to loop over arrays and objects in JavaScript, and the tradeoffs are a common cause of confusion.

The for and for/in looping constructs give you access to the index in the array, not the actual element. For example, suppose you want to print out the values stored in the below array:

const arr = ['a', 'b', 'c'];

With for and for/in, you need to print out arr[i]:

for (let i = 0; i < arr.length; ++i) {
console.log(arr[i]);
}
for (let i in arr) {
console.log(arr[i]);
}

With the other two constructs, forEach() and for/of, you get access to the array element itself. With forEach() you can access the array index i, with for/of you cannot.

const arr = ['a', 'b', 'c'];arr.forEach((key, index) => console.log(key));

for (const element of arr) {
console.log(element);
}
// expected output: "a"
// expected output: "b"
// expected output: "c"

Conclusions

Generally, for/of is the most robust way to iterate over an array in JavaScript. It is more concise than a conventional for loop and doesn't have as many edge cases as for/in and forEach().

The major downsides of for/of is that you need to do extra work to access the index , and you can't chain like you can with forEach(). forEach() comes with several caveats and should be used sparingly, but there are numerous cases where it makes code more concise.

(1) To access the current array index in a for/of loop, you can use the Array#entries() function.

for (const [i, v] of arr.entries()) {
console.log(i, v); // Prints "0 a", "1 b", "2 c"
}

Experience with Front-end Technologies and MERN / MEAN Stack. Working on all Major UI Frameworks like React, Angular.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store