- What is Closure in JavaScript?
- setTimeout Function in JavaScript
- Different Types of Functions and Terminologies
- Callback Functions in JavaScript
All answers are inspired by Akshay Saini's Namaste JavaScript Series
- Function bundled along with it's lexical scope is Closure.
- Lexical Scope Environment: If function needs to access specific variable then it first goes to its local scope. When it doesn't find locally, it goes to its lexical parent. So it's around the function
y(), if you consider the example below.var a = 7;is in lexical parent of function y.
function x() {
var a = 7;
function y() {
console.log(a);
}
return y;
}
var z = x();
console.log(z); // value of z is entire code of function y.A closure is a function that has access to its outer function scope even after the function has returned. Meaning, A closure can remember and access variables and arguments reference of its outer function even after the function has returned.
- Module Design Pattern
- Currying
- Functions like
once - memoize
- setTimeouts
- Iterators etc.
- Overconsumption of Memory
Time, Tide & JavaScript wait for none. By Akshay Saini
- Below is the example of setTimeout function:
function x() {
var i = 1;
setTimeout(function() {
console.log(i);
}, 3000);
console.log("Hello");
}
x();Output
Hello
1 (after 3 seconds)
- Javascript assign the memory for the function x somewhere and set the timer of 3 seconds for it & JS Engine continues to execute next lines. So it prints
Hellofirst and then after 3 seconds, it prints 1.
We write below code as obvious
function x(){
for(var i = 1; i<=5 ; i++){
setTimeout(
function(){console.log(i)},
i * 1000
);
}
}
x();Output
6
6
6
6
6
This is happeneing because JS engine will not wait while timer is running. So before timer gets completed, loop complete and has latest value as 6 in its memory location. So for each i, it points to same memory location having value as 6. This issue can be resolved by using either closures or let.
function x(){
for(let i = 1; i<=5 ; i++){
setTimeout(
function(){console.log(i)},
i * 1000
);
}
}
x();As let variable has block scope, so it will take seperate memory location for each time i iterates and has different value in it.
function x(){
for(var i = 1; i<=5 ; i++){
function timer(a){
setTimeout(
function(){console.log(a)},
a * 1000
);
}
timer(i);
}
}
x();Each time loops runs, it calls the function timer() and pass different value. So each function iteration has seperate value and memory pointer pointing to it.
Below way of writing function is called function statement:
function x() {
console.log('test');
}
x(); //testBelow way of writing a function is called function expression:
var a = function() {
console.log('test2');
}
a(); //test2Key difference between function statement and expression is the hoisting only. We can't call function before definining in case of expression, while we can call function before defining in function statement.
a(); //function a
b(); //Uncaught TypeError: b is not a function
function a() {console.log('function a');} //Function Statement
var b = function() {console.log('function b');} //Function ExpressionNote: In case of function expression, b is only placeholder in the memory location and value is undefined. So once execution context comes to the line where it defined then only b's value set as function. Before that we can't call the function same as we can call in function statement.
Anonymous function is a function without the name. We can't use it in below way.
function() {
//...
}- This results into an error as
Uncaught SyntaxError: Function statements require a function name. - We can use anonymous function as value.
- We can assign it to variable(as we did in function expression), pass it to a function arguments etc. Examples:
//Example 1
var anonym = function() { //... }
//Example 2
function a(func){
console.log(func);
}
a(function(){console.log('this is function b');}); //prints "ƒ (){console.log('this is function b');}"We can pass function as arguments into another function and also we can return the function as a value from function. This ability of passing and returning a function is called First Class Function. This is also available in other programming languages.
// passing the function as arguments
var b = function(param1) {
console.log(param1); // prints " f() {} "
}
b(function(){});
//returning the function as value
var b = function(param1) {
return function() {
}
}
console.log(b()); // prints "ƒ () { }"This is also called first class citizens.
Named function expression is same as function expression, but this function has a name instead of being anonymous.
var a = function xyz() {
console.log('test2');
}
a(); //test2Note: We can't call function by xyz()
Parameters: It's labels or identifiers used when defining function.
Arguments: When we call function and we pass the value into function. Those values called arguments.
function a(param1, param2){
console.log(param1, param2);
}
a(7,8);In above example, param1 & param2 is parameters. While 7 & 8 is referred as arguments.
- Callback Function is a function passed as argument to another function. It's called callback function because it will get called sometime later during execution.
- For e.g. setTimeout() has first argument as callback function and that callback function will get called once timer got expired which passed as second argument.
- Once javascript execution completed, callstack gets empty. But if there's still setTimout()'s timer is running then once timer gets expired then callback function will be added to callstack after that timeout time period.
setTimeout(function(){
console.log('after 3 seconds');
}, 3000);- Synchronous: Javascript executes all the statements one by one.
- Single threaded language: It means that JavaScript has only single callstack which is used to execute the program. Everything in javascript executed, will be executed from this one call stack only.
- If there is any function in your code which does very heavy operation (and e.g. if it takes 30 seconds to complete the execution of whole function). During this time, JS won't be able to execute any other of code as there's only one call stack. This event is called blocking the main thread.
- As there's only one call stack, so we should never block our main thread. We should always try to use async operations for things which takes time.(e.g. setTimeout)
- We will create a button in html and attach event to it.
// index.html
<button id="clickMe">Click Me!</button>
// index.js
document.getElementById("clickMe").addEventListener("click", function xyz(){ //when event click occurs, this callback function (xyz) is called into callstack
console.log("Button clicked");
});- Let's implement counter which will take care of how many times the button has clicked. Using global variable (This is not good practice as anyone can change
countvariable)
let count = 0;
document.getElementById("clickMe").addEventListener("click", function xyz(){
console.log("Button clicked", ++count);
});- Use closures for Data Abstraction
function attachEventListener() {
let count = 0;
document.getElementById("clickMe").addEventListener("click", function xyz(){
console.log("Button clicked", ++count);
});
}
attachEventListener();- In Second example, once execution of javascript gets finished. Event Listener has been added in your browser with the closures. It has lexical scope and count variable as well. Once someone click on the button, that count value gets increased by one.
- Event listeners are heavy as they form the closures and store everything around it in the browser. Because event can be triggered anytime even after the JS execution gets completed for given script.
- So even when call stack is empty, EventListener won't free up memory allocated to count as it doesn't know when it may need count again.
- We should remove event listeners when we don't need them (garbage collected). onClick, onHover, onScroll all in a page can slow it down heavily.